libcoro:在c++中支持coroutine
起因
在第一个版本的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的更多相关文章
- Unity3D中的Coroutine详解
Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这样的代码. 疑问: yield是什么? Coroutine是什么? unity的coroutin ...
- 【Unity3D/C#】Unity3D中的Coroutine详解
Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这样的代码. 疑问: yield是什么? Coroutine是什么? unity的coroutin ...
- Unity3D中的Coroutine具体解释
本文太乱,推荐frankjfwang的:全面解析Coroutine技术 Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这种代码. 疑问: yie ...
- 在DirectShow中支持DXVA 2.0(Supporting DXVA 2.0 in DirectShow)
这几天在做dxva2硬件加速,找不到什么资料,翻译了一下微软的两篇相关文档.并准备记录一下用ffmpeg实现dxva2,将在第三篇写到.这是第二篇.,英文原址:https://msdn.microso ...
- C#中的yield return与Unity中的Coroutine(协程)(下)
Unity中的Coroutine(协程) 估计熟悉Unity的人看过或者用过StartCoroutine() 假设我们在场景中有一个UGUI组件, Image: 将以下代码绑定到Image using ...
- iOS6:在你的企业系统中支持Passbook
前言 这是一篇翻译,感谢Jonathan Tang. 原文地址:iOS 6 Tutorial: Supporting Passbook within Your Enterprise Systems 正 ...
- webView中支持input的file的选择和alert弹出
alert()弹出 input的file现选择(特别说明:不同的android版本弹出的样式不同,选择文件后自动上传) webView.setWebChromeClient(new WebChrome ...
- EntityFramework中支持BulkInsert扩展
EntityFramework中支持BulkInsert扩展 本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 前言 很显然,你应该不至于使用 Ent ...
- 在SOUI中支持高分屏显示
和手机屏幕一样,高分屏在PC上使用越来越多.传统的桌面程序都是像素为单位进行UI布局,而且是适配传统的96dpi的显示器的.这就导致这些程序在高分屏上显示很小,用户用起来很难受. 虽然windows系 ...
随机推荐
- hive 存储,解析,处理json数据
hive 处理json数据总体来说有两个方向的路走 1.将json以字符串的方式整个入Hive表,然后通过使用UDF函数解析已经导入到hive中的数据,比如使用LATERAL VIEW json_tu ...
- Laravel-admin 七牛云上传文件到七牛云出现卡顿失败情况
由于所做项目需要管理后台众多,所以选择了Laravel-admin后台框架进行开发.节省了权限控制以及页面处理等问题的时间 Laravel-admin文档地址 http://laravel-admin ...
- --save-dev 和 --save的区别
1. 我们在使用npm install xx --save-dev / --save安装模块或插件的时候,会将他们写入到 package.json 文件,那到底有什么区别呢? --save-dev:会 ...
- Oracle中打印99乘法表的13种方法
--实现1: select r1 || '*' || r1 || '=' || r1 * r1 A, decode(r2, '', '', r2 || '*' || r1 || '=' || r2 * ...
- Django REST Framework 最佳实践
Django REST framework 是一个强大且灵活的工具包,用以构建Web APIs. 为什么要使用REST framework? - 在线可视的API,对于赢得你的开发者们十分有用 - 验 ...
- Swift:消除Null值
由于在现代编程语言中这个无所不在的概念,许多程序猿可能倾向于相信null值是一个必须存在的瑕疵,创建一个没有它的编程语言是不可能的.他们可能会惊奇那些许多没有null值活的也很好的语言,这带来的结果就 ...
- Android输入事件详解
输入事件 在 Android 系统中,从用户与应用的交互中截获事件的方法不止一种.如考虑截获用户界面内的事件,则可从用户与之交互的特定视图对象中捕获事件. 为此,View 类提供了多种方法. 在您将用 ...
- 理解性能的奥秘——应用程序中慢,SSMS中快(6)——SQL Server如何编译动态SQL
本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(5)--案例:如何应对参数嗅探 我们抛开参数嗅探的话题,回到了本系列的最 ...
- SceneKit做一个旋转的地球效果
SceneKit可以用寥寥几行帮你完成很多OpenGL复杂的3D设置代码,下面本猫就带大家完成一个旋转的3D地球的场景. 首先需要地球表面图片,将其导入到Xcode中: 我们用SceneKit内置的几 ...
- Tomcat的系统安全管理
Tomcat是一个Web容器,我们开发的Web项目运行在Tomcat平台,这就好比将一个应用嵌入到一个平台上面运行,要使嵌入的程序能正常运行,首先平台要能安全正常运行.并且要最大程度做到平台不受嵌入的 ...