起因

在第一个版本的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的更多相关文章

  1. Unity3D中的Coroutine详解

    Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这样的代码. 疑问: yield是什么? Coroutine是什么? unity的coroutin ...

  2. 【Unity3D/C#】Unity3D中的Coroutine详解

    Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这样的代码. 疑问: yield是什么? Coroutine是什么? unity的coroutin ...

  3. Unity3D中的Coroutine具体解释

    本文太乱,推荐frankjfwang的:全面解析Coroutine技术 Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这种代码. 疑问: yie ...

  4. 在DirectShow中支持DXVA 2.0(Supporting DXVA 2.0 in DirectShow)

    这几天在做dxva2硬件加速,找不到什么资料,翻译了一下微软的两篇相关文档.并准备记录一下用ffmpeg实现dxva2,将在第三篇写到.这是第二篇.,英文原址:https://msdn.microso ...

  5. C#中的yield return与Unity中的Coroutine(协程)(下)

    Unity中的Coroutine(协程) 估计熟悉Unity的人看过或者用过StartCoroutine() 假设我们在场景中有一个UGUI组件, Image: 将以下代码绑定到Image using ...

  6. iOS6:在你的企业系统中支持Passbook

    前言 这是一篇翻译,感谢Jonathan Tang. 原文地址:iOS 6 Tutorial: Supporting Passbook within Your Enterprise Systems 正 ...

  7. webView中支持input的file的选择和alert弹出

    alert()弹出 input的file现选择(特别说明:不同的android版本弹出的样式不同,选择文件后自动上传) webView.setWebChromeClient(new WebChrome ...

  8. EntityFramework中支持BulkInsert扩展

    EntityFramework中支持BulkInsert扩展 本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 前言 很显然,你应该不至于使用 Ent ...

  9. 在SOUI中支持高分屏显示

    和手机屏幕一样,高分屏在PC上使用越来越多.传统的桌面程序都是像素为单位进行UI布局,而且是适配传统的96dpi的显示器的.这就导致这些程序在高分屏上显示很小,用户用起来很难受. 虽然windows系 ...

随机推荐

  1. 吴恩达深度学习第1课第3周编程作业记录(2分类1隐层nn)

    2分类1隐层nn, 作业默认设置: 1个输出单元, sigmoid激活函数. (因为二分类); 4个隐层单元, tanh激活函数. (除作为输出单元且为二分类任务外, 几乎不选用 sigmoid 做激 ...

  2. Docker命令查询

    基本语法 docker [OPTIONS] COMMAND [arg...] 一般来说,Docker 命令可以用来管理 daemon,或者通过 CLI 命令管理镜像和容器.可以通过 man docke ...

  3. Docker端口映射实现

    默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器. 容器访问外部实现 容器所有到外部网络的连接,源地址都会被NAT成本地系统的IP地址.这是使用 iptables 的源地址伪装 ...

  4. Bootstrap3 栅格系统-列排序

    通过使用 .col-md-push-* 和 .col-md-pull-* 类就可以很容易的改变列(column)的顺序. <div class="row"> <d ...

  5. 热烈庆祝自已厉精13年开发的 DB查询分析器 7.01(最新版本) 在中关村在线本月获得近6000次的下载量

    中国本土程序员马根峰(CSDN专访马根峰:海量数据处理与分析大师的中国本土程序员)推出的个人作品----万能数据库查询分析器,中文版本 DB 查询分析器.英文版本DB Query Analyzer.它 ...

  6. docker 部署cassandra

    摘要 本文主要介绍在redhat7 平台,利用docker 部署cassandra 集群,除了介绍基本的部署步骤,另外主要 讨论类似于cassandra 这种分布式集群系统部署 docker如何进行网 ...

  7. Scala:提取器(Extractor)

    http://blog.csdn.net/pipisorry/article/details/52902671 提取器是从传递给它的对象中提取出构造该对象的参数. Scala 标准库包含了一些预定义的 ...

  8. Scala:集合类型Collection和迭代器

    http://blog.csdn.net/pipisorry/article/details/52902549 Scala Collection Scala 集合分为可变的和不可变的集合. 可变集合可 ...

  9. arm-none-eabi-g++ -Xlinker -T "../LF3Kmonitor.ld" -Xlinker -Map="Bogota_ICT_V.map"-ram-hosted.ld -mc

    1.arm-none-eabi-g++:是编译ARM裸板用的编译器,不依赖于操作系统. 2.-Xlinker -T "../LF3Kmonitor.ld" -Xlinker -Ma ...

  10. C++ 中const作用

    一.对const与#define的特点及区别的理解 #define只是用来做文本替换的,#define常量的生命周期止于编译期,它存在于程序的代码段,在实际程序中它只是一个常数,一个命令中的参数,并没 ...