libcoro:在c++中支持coroutine
2014-03-05 14:28
134 查看
起因
在第一个版本的libtnet开发完成之后,我一直在思考如何让异步方式的网络编程更加简单。虽然libtnet通过c++ shared_ptr以及function等技术很大程度上面解决了异步代码编写的一些问题,但是仍然会出现代码逻辑被强制拆分的情况。而这个则是项目中童鞋无法很好的使用其进行开发的原因。
所以我考虑让libtnet支持coroutine。
Coroutine
第一次接触coroutine的概念是在lua里面,记得当时想了很久才算弄明白了coroutine的使用以及原理。在lua中,coroutine的使用如下:co = coroutine.create(function () print("begin yield") coroutine.yield() print("after yield") end) coroutine.resume(co) print("after resume") coroutine.resume(co)
我们可以通过resume执行一个新创建或者已经被挂起的coroutine,通过yield挂起当前的coroutine,这样就可以实现类似多线程方式下面的多任务调度。
至于coroutine的原理,很多地方都有说明,主要就在于每个coroutine都有自己的堆栈,这样当coroutine挂起的时候,它的当前执行状态会被完整保留,下次resume的时候就可以接着执行了。
而使用coroutine的好处,我觉得最大的一点在于它将拆分的异步逻辑同步化了,更利于代码编写。
在使用python tornado的时候,我们开始阶段写了太多的callback回调,以至于代码的维护非常困难,而这个则在引入greenlet后有了明显好转。
而后续在使用go语言中,因为它原生的支持coroutine(其实在go里面更准确的说法应该是goroutine),写代码非常的方便,所以现在go已经成为了我服务器的首选开发语言,我也用它开发了多个项目(如mixer,一个mysql proxy),并且已经在公司项目中实施。
当然,使用coroutine并不是毫无缺点的:
每个coroutine都需要维护自己的堆栈,当我们需要创建数以百万计的coroutine的时候,内存的开销就需要考虑了。
coroutine的切换,都需要保留当前的上下文环境,以便于下次resume的时候接着执行,如果coroutine切换频繁,开销也不小。
libcoro
很早之前使用luajit的时候,我就知道可以在c++中实现coroutine的功能,在linux中,这通过makecontext,swapcontext等相关函数实现。虽然也可以通过setjmp/longjmp这两个古老的函数实现,但看了luajit的coco就知道,即使在linux下面,它也需要写很多define宏去适配。所以,我只考虑使用makecontext这套函数族来实现coroutine。虽然swapcontext会有性能问题,详见这里,但早期我还不打算对其进行性能优化。
libcoro是一个简单的c++ coroutine库,只支持linux(因为我们的服务器只有linux的)。
在接口上面,libcoro参考的是lua的coroutine的接口设计,使用非常简单:
void func1() { coroutine.yield(); } void func2(Coro_t co1) { coroutine.resume(co1); coroutine.yield(); } void func() { Coro_t co1 = coroutine.create(std::bind(&func1)); coroutine.resume(co1); Coro_t co2 = coroutine.create(std::bind(&func2, co1)); coroutine.resume(co2); coroutine.resume(co2); } int main() { Coro_t co = coroutine.create(std::bind(&func)); coroutine.resume(co); return 0; }
coroutine.create创建一个coroutine,参数为一个std::function,这样我们就可以通过std::bind非常方便的实现函数闭包了。
coroutine.resume唤醒一个挂起或者新建的coroutine。
coroutine.yield挂起当前coroutine。
coroutine.running获取当前运行的coroutine,如果是主线程调用,则返回0。
coroutine.status获取coroutine的状态。
后续我考虑将libtnet支持coroutine,不过这可能会成为一个新的网络库了。
相关文章推荐
- libcoro:在c++中支持coroutine
- c++支持coroutine的简单示例
- UTF-8到acsii的转换(让自己的C++程序支持多语言)
- [C++]DES加密解密工具2.1及其代码——支持字符串及文件加密,支持3重DES
- librdkafka 0.8 应用到C++代码中应当使用C的链接方式
- 【linux/c/c++】linux 的服务器环境安装支持c/c++等操作
- 最新的受到支持的Visual C++ Redistributable Packages 下载地址
- C/C++ 标准以及各种编译器对标准的支持情况(不断完善中)
- error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
- 在VC中使用Matrix<LIB>C++数学库
- 为什么C++支持重载,C语言不支持
- Visual C/C++ 6.0 为何不支持新的SDK
- C++文件搜索[非MFC,支持通配符,子目录,隐藏文件,只读文件,支持命令行]
- error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默
- 【window10下notepad++编辑器安装与配置C和C++(支持C++primer)】
- configure: error: C++ preprocessor "/lib/cpp" fails sanity check
- gcc对C++ Standards的支持
- UCS-2与UTF8之间的选择(4)--linux中各编码字符串的C/C++输出支持及方式比较
- Log4cpp:为中小型C++项目加上log支持
- [安卓]成功在android平台用ndk上编译libcurl+openssl支持https