Skip to content

Commit

Permalink
update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
idealvin committed Aug 9, 2021
1 parent 7ccd1cf commit 4a60e17
Show file tree
Hide file tree
Showing 22 changed files with 1,069 additions and 963 deletions.
129 changes: 109 additions & 20 deletions content/cn/about/co.md
@@ -1,6 +1,6 @@
---
weight: 1
title: "一文了解 CO"
title: "简介"
---


Expand All @@ -26,6 +26,7 @@ CO 在 [github](https://github.com/idealvin/co) 上以 [MIT](https://mit-license

## 快速上手


### 编译

建议安装 [xmake](https://github.com/xmake-io/xmake),在 CO 根目录执行如下命令构建所有子项目:
Expand Down Expand Up @@ -54,7 +55,6 @@ xmake r co

最简单的,可以直接包含 [co/all.h](https://github.com/idealvin/co/blob/master/include/co/all.h),使用 CO 中的所有特性。如果担心影响编译速度,也可以只包含需要用到的头文件,如包含 [co/co.h](https://github.com/idealvin/co/blob/master/include/co/co.h),可以使用 co/flag, co/log 以及协程相关的所有特性。


```cpp
#include "co/all.h"

Expand Down Expand Up @@ -213,7 +213,7 @@ DEF_test(os) {
} // namespace test
```

上面是一个简单的例子,`DEF_test` 宏定义了一个测试单元,实际上就是一个函数(类中的方法)。`DEF_case` 宏定义了测试用例,每个测试用例实际上就是一个代码块。用户可以将不同的测试单元,放到同一个 C++ 项目中,main 函数一般只需要下面几行:
上面是一个简单的例子,`DEF_test` 宏定义了一个测试单元,实际上就是一个函数(类中的方法)。`DEF_case` 宏定义了测试用例,每个测试用例实际上就是一个代码块。多个测试单元可以放到同一个 C++ 项目中,main 函数一般只需要下面几行:

```cpp
#include "co/unitest.h"
Expand All @@ -238,11 +238,16 @@ xmake r unitest -os # 仅运行 os 单元中的测试用例

CO 实现了类似 [golang](https://github.com/golang/go) 的协程,它有如下特性:

- 支持多线程调度,默认线程数为系统 CPU 核数。
- 多线程调度,默认线程数为系统 CPU 核数。
- 共享栈,同一线程中的协程共用若干个栈(大小默认为 1MB),内存占用低,Linux 上的测试显示 1000 万协程只用了 2.8G 内存(仅供参考)。
- 各协程之间为平级关系,可以在任何地方(包括在协程中)创建新的协程。
- 支持系统 API hook (Windows/Linux/Mac),可以在直接在协程中使用三方网络库。

- 支持系统 API hook (Windows/Linux/Mac),可以直接在协程中使用三方网络库。
- 协程化的 [socket API](../../co/coroutine/#协程化的-socket-api)
- 协程同步事件 [co::Event](../../co/coroutine/#协程同步事件coevent)
- 协程锁 [co::Mutex](../../co/coroutine/#协程锁comutex)
- 协程池 [co::Pool](../../co/coroutine/#协程池copool)
- channel [co::Chan](../../co/coroutine/#channelcochan)
- waitgroup [co::WaitGroup](../../co/coroutine/#waitgroupcowaitgroup)


#### 创建协程
Expand Down Expand Up @@ -279,7 +284,7 @@ for (size_t i = 0; i < s.size(); ++i) {

#### channel

CO 实现了 `co::Chan`,类似于 golang 中的 channel,它是一个模板类,模板参数可以是内置类型、指针类型或者其他可以进行内存拷贝的结构体或类
[co::Chan](../../co/coroutine/#channelcochan),类似于 golang 中的 channel,可用于在协程之间传递数据

```cpp
#include "co/co.h"
Expand All @@ -298,29 +303,113 @@ DEF_main(argc, argv) {
}
```
上面是个简单的例子,需要注意,**co::Chan 必须在协程中使用**,因此代码中用 `DEF_main` 定义 main 函数,让 main 函数中的代码也运行在协程中。
**channel 的读写操作必须在协程中进行**,因此上述代码中用 `DEF_main` 定义 main 函数,让 main 函数中的代码也运行在协程中。
另外,代码中的 channel 对象在栈上,而 CO 采用的是共享栈实现方式,一个协程栈上的数据可能被其他协程覆盖,**协程间一般不能直接共享栈上的数据**,因此代码中的 lambda 采用了**按值捕获**的方式,将 channel 拷贝了一份,传递到新建的协程中。channel 的拷贝操作只是将内部引用计数加 1,几乎不会对性能造成影响。
代码中的 channel 对象在栈上,而 CO 采用的是共享栈实现方式,一个协程栈上的数据可能被其他协程覆盖,**协程间一般不能直接通过栈上的数据通信**,因此代码中的 lambda 采用了**按值捕获**的方式,将 channel 拷贝了一份,传递到新建的协程中。channel 的拷贝操作只是将内部引用计数加 1,几乎不会对性能造成影响。
用户在创建 channel 时,还可以加上超时时间
创建 channel 时可以像下面这样加上超时时间
```cpp
co::Chan<int> ch(8, 1000);
go([ch]() {
ch << 7;
if (co::timeout()) LOG << "write to channel timeout";
});
int v = 0;
ch >> v;
if (!co::timeout()) LOG << "v: " << v;
```

co::Chan 构造函数的第一个参数是内部队列长度,第二个参数是超时时间,单位为毫秒。用户在 channel 读写操作后,可以用 `co::timeout()` 判断是否超时。
channel 读写操作结束后,可以调用 `co::timeout()` 判断是否超时,这种方式比 golang 中基于 select 的实现方式更简单。

CO 中的 channel 基于内存拷贝实现,传递的数据类型可以是内置类型、指针类型,或者**拷贝操作具有简单的内存拷贝语义的结构体类型**。像 `std::string` 或 STL 中的容器类型,拷贝操作不是简单的内存拷贝,一般不能直接在 channel 中传递,详情见 [co::Chan 参考文档](../../co/coroutine/#channelcochan)


#### waitgroup

[co::WaitGroup](../../co/coroutine/#waitgroupcowaitgroup),类似于 golang 中的 `sync.WaitGroup`,可用于等待协程或线程的退出。

```cpp
#include "co/co.h"

DEF_main(argc, argv) {
FLG_cout = true;

co::WaitGroup wg;
wg.add(8);

for (int i = 0; i < 8; ++i) {
go([wg]() {
LOG << "co: " << co::coroutine_id();
wg.done();
});
}

wg.wait();
return 0;
}
```
### 网络编程
CO 提供了一套协程化的 [socket API](../../co/coroutine/#协程化的-socket-api),它们大部分形式上与原生的 socket API 基本一致,熟悉 socket 编程的用户,可以轻松的用同步的方式写出高性能的网络程序。另外,CO 也实现了更高层的网络编程组件,包括 [TCP](../../co/net/tcp/)、[HTTP](../../co/net/http/) 以及基于 [JSON](../../co/json/) 的 [RPC](../../co/net/rpc/) 框架,它们兼容 IPv6,同时支持 SSL,用起来比 socket API 更方便。这里只简单的展示一下 HTTP 的用法,其余的可以查看参考文档。
**静态 web server**
```cpp
#include "co/flag.h"
#include "co/log.h"
#include "co/so.h"
DEF_string(d, ".", "root dir"); // Specify the root directory of the web server
int main(int argc, char** argv) {
flag::init(argc, argv);
log::init();
so::easy(FLG_d.c_str()); // mum never have to worry again
return 0;
}
```


**HTTP server**

#### 协程
```cpp
http::Server serv;

serv.on_req(
[](const http::Req& req, http::Res& res) {
if (req.is_method_get()) {
if (req.url() == "/hello") {
res.set_status(200);
res.set_body("hello world");
} else {
res.set_status(404);
}
} else {
res.set_status(405); // method not allowed
}
}
);

serv.start("0.0.0.0", 80); // http
serv.start("0.0.0.0", 443, "privkey.pem", "certificate.pem"); // https
```
**HTTP client**
```cpp
void f() {
http::Client c("https://github.com");
c.get("/");
LOG << "response code: "<< c.response_code();
LOG << "body size: "<< c.body_size();
LOG << "Content-Length: "<< c.header("Content-Length");
LOG << c.header();
c.post("/hello", "data xxx");
LOG << "response code: "<< c.response_code();
}
go(f);
```
13 changes: 13 additions & 0 deletions content/cn/about/contact.md
@@ -0,0 +1,13 @@
---
weight: 2
title: "联系"
---

**联系方式**

- Email: idealvin@qq.com
- github: [https://github.com/idealvin/co](https://github.com/idealvin/co)
- gitee: [https://gitee.com/idealvin/co](https://gitee.com/idealvin/co)
- zhihu: [idealvin](https://www.zhihu.com/people/vin.cc)

CO 目前有一个技术交流微信群,有兴趣加群的朋友,可以给 Alvin 发邮件,或在知乎上私信 idealvin。
26 changes: 26 additions & 0 deletions content/cn/about/sponsor.md
@@ -0,0 +1,26 @@
---
weight: 3
title: "赞助💕"
---


## 赞助

CO 是一个个人项目,如果您有意向赞助 CO,可以联系 Alvin(idealvin@qq.com),我们将会在这里展示您的 logo、网址等信息,同时将为您提供更好的技术服务。非常感谢🙏




## 咖啡

如果您喜欢 CO,也可以考虑给作者来杯咖啡,非常感谢🙏


- 微信

![wx.png](/images/wx.png)


- 支付宝

![zfb.png](/images/zfb.png)
2 changes: 1 addition & 1 deletion content/cn/co/coroutine.md
Expand Up @@ -713,7 +713,7 @@ DEF_main(argc, argv) {
}
```
上面的代码中,channel 对象在栈上,因此在 lambda 中使用了**按值捕获**的方式,以拷贝的方式将 channel 传递到协程中
上述代码中的 channel 对象在栈上,而 CO 采用的是共享栈实现方式,一个协程栈上的数据可能被其他协程覆盖,**协程间一般不能直接通过栈上的数据通信**,因此代码中的 lambda 采用了**按值捕获**的方式, channel 拷贝了一份,传递到新建的协程中。channel 的拷贝操作只是将内部引用计数加 1,几乎不会对性能造成影响
Expand Down
13 changes: 13 additions & 0 deletions content/cn/co/def.md
Expand Up @@ -12,6 +12,7 @@ include: [co/def.h](https://github.com/idealvin/co/blob/master/include/co/def.h)
### 定长整数类型

`def.h` 定义了如下的 8 种整数类型:

```cpp
typedef int8_t int8;
typedef int16_t int16;
Expand All @@ -22,6 +23,7 @@ typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
```

这些类型在不同平台的长度是一致的,不存在可移植性问题。[Google Code Style](https://google.github.io/styleguide/cppguide.html#Integer_Types) 建议除了 int,不要使用 short, long, long long 等内置整数类型。


Expand All @@ -31,19 +33,23 @@ typedef uint64_t uint64;


### 整型最大、最小值

```cpp
MAX_UINT8 MAX_UINT16 MAX_UINT32 MAX_UINT64
MAX_INT8 MAX_INT16 MAX_INT32 MAX_INT64
MIN_INT8 MIN_INT16 MIN_INT32 MIN_INT64
```

这些宏分别表示 8 种整数类型的最大、最小值。



### DISALLOW_COPY_AND_ASSIGN

这个宏用于禁止 C++ 类中的拷贝构造函数与赋值操作。

- 示例

```cpp
class T {
public:
Expand All @@ -53,22 +59,27 @@ class T {
```
### __forceinline
[__forceinline](https://docs.microsoft.com/en-us/cpp/cpp/inline-functions-cpp?view=vs-2019#inline-__inline-and-__forceinline) 是 VS 中的关键字,放在函数定义开头,强制内联函数,linux 与 mac 平台用下面的宏模拟:
```cpp
#define __forceinline __attribute__((always_inline))
```



### __thread

[__thread](https://gcc.gnu.org/onlinedocs/gcc-4.7.4/gcc/Thread-Local.html) 是 gcc/clang 中的关键字,用于支持 [TLS](https://wiki.osdev.org/Thread_Local_Storage),windows 平台用下面的宏模拟:

```cpp
#define __thread __declspec(thread)
```
- 示例
```cpp
// get id of the current thread
__forceinline unsigned int gettid() {
Expand All @@ -79,11 +90,13 @@ __forceinline unsigned int gettid() {
```



### unlikely

这个宏用于分支选择优化,仅支持 gcc/clang。

- 示例

```cpp
// 与 if (v == 0) 逻辑上等价,但提示编译器 v == 0 的可能性较小
if (unlikey(v == 0)) {
Expand Down
28 changes: 28 additions & 0 deletions content/cn/co/defer.md
@@ -0,0 +1,28 @@
---
weight: 2
title: "defer"
---

include: [co/defer.h](https://github.com/idealvin/co/blob/master/include/co/defer.h).


## defer

`defer` 是 CO 提供的一个宏,它实现了类似 golang 中 defer 的功能。

```cpp
#include "co/defer.h"
#include "co/time.h"
#include "co/log.h"
#include "co/json.h"

void f(const Json& req, Json& res) {
Timer t;
LOG << "req: " << req;
defer(LOG << "res: " << res << ", time elapse: " << t.us() << "us");

// do something here
}
```
上面的例子中,`defer` 中的代码将在函数 `f` 结束时执行,从而打印出函数的输出及调用时间。

0 comments on commit 4a60e17

Please sign in to comment.