关于Coroutine

说到coroutine就不的不说subroutine,也就是我们常用到的一般函数。调用一个函数开始执行,然后函数执行完成后就退出,再次调用的时候,再从头开始,调用之间是没有保存状态的;但是coroutine是可以在退出时如果再次被调用,可以从上一次退出的点继续执行。也就是说coroutine的调用之间是会保存状态的。如果有多个coroutine,就可以反复调用,但是两个coroutine相互前进。当一个coroutine退出时,不是return,而是yield,表示把当前的执行权交由下一个coroutine处理,或者交出一个结果值。coroutine与我们常用到的thread有点类似,一个thread会执行一个我们指定的函数,然后当该函数调用一个阻塞IO或者同步等待一个事件或者消息时,就会被操作系统调度到等待队列,当完成或者事件响应后,线程就会继续从等待的地方执行。thread和coroutine最大的区别就是调度方式的区别,前者一般都是基于时间片的抢占式调度,而coroutine都是协作式调度。

话说回来,我们一般用的函数可以很容易的转换到coroutine。coroutine中还有一个特例,就是generator. Generator可以像一般的coroutine一样从上一次返回的地方继续执行,也可以yield多次,也可以把自己挂起,但是一般的coroutine可以在yield时指定下一个要执行的coroutine,而generator不能这么做。因此,generator一般用来实现迭代器。

Coroutine可以很方便的用来实现状态机。 Coroutine实现状态机会让代码变的更可读。比如实现一个SMTP客户端,用的是event-driven范式实现,那么就需要记录每次处理的状态,代码会变得异常复杂。假设你还是使用的event-driven范式实现,但是你用到了coroutine,coroutine内部的流程就是一般SMTP的流程,只是需要每一步请求发送后就退出,然后当收到回应包时event-driven引擎又再次调用了你的coroutine,直接到了上一次退出的地方,是不是感觉更清爽?

因为coroutine比thread相比要轻量的多,thread在操作系统层面实现,调度方式涉及到CPU上下文的切换,和coroutine的协作式调度相比要重了一些,在高并发场景中针对每个请求用thread承载会变的非常低效,但是coroutine反而容易在语言层面或者库层面实现,因此调度代价要低很多。像Lua的coroutine实现要求程序员自己调用yield自己调度,比较麻烦,但是假设像Golang,Erlang等语言把显示的协作调度隐藏起来,让程序员专注功能实现,会更容易让人接受。在golang中叫coroutine叫goroutine,当goroutine中调用了阻塞操作或者Channel的读写操作时,就会导致对应的goroutine得到执行,当完成后又会被调度回来继续执行,这种同步的编程方式可以让并发场景进行简化,让逻辑变得更清晰。Golang的这种实现把一般的显示的协作调度隐藏起来,更容易被程序员接受。

C语言实现的Coroutine

一般Coroutine多在带有GC机制的语言中实现,像在C/C++下实现coroutine会比较复杂和麻烦,不过还是有很多不同的实现,比如Russ Cox实现的libtask库,C++下的boost.coroutine库等等。其中我觉着最亮的是 大牛Simon Tatham(putty的作者)基于Duff's Device实现的版本《Coroutine in C》。其中展示了如何把一个复杂的decompressor用coroutine简化的。Simon大神实现了两种coroutine,一种是基于static变量保存状态的,另外一种是通过参数传递一个指针的指针保存状态的。后者更通用一些。详细代码点击这里

boost.asio.coroutine

asio中的coroutine的实现与上面Simon的第一种实现一样。所以没有太多可说的。boost.asio.coroutine的使用非常简单,在自己代码中包含coroutine.hpp和yield.hpp,创建一个类,派生自coroutine类。然后可以根据自己的业务要求写相应的coroutine了。当然,也可以把coroutine类作为自己的成员变量组合到自己的类中。

asio的作者也对其做了详细的说明《A potted guide to stackless coroutines》,同时还写了专门个使用指南《Composed operations, coroutines and code makeover》

总结

想用Coroutine建议还是用些现代的新语言吧,比如Golang, Erlang, Scala等。

The Coroutine的更多相关文章

  1. Coroutine in Java - Quasar Fiber实现--转载

    转自 https://segmentfault.com/a/1190000006079389?from=groupmessage&isappinstalled=0 简介 说到协程(Corout ...

  2. c coroutine

    今天看了下云风c coroutine  代码 博客,发现 coroutine 实现原理其实还比较简单,就用户态栈切换,只需要几十行汇编,特别轻量级. 具体实现 1. 创建一个coroutine: 也就 ...

  3. lua coroutine for iterator

    背景 前面的文章演示了使用闭包函数实现 状态的迭代器. 本文演示使用 coroutine来产生迭代器的例子. coroutine迭代器例子 -- 遍历二叉树 local binary_tree = { ...

  4. python中的generator(coroutine)浅析和应用

    背景知识: 在Python中一个function要运行起来,它在python VM中需要三个东西. PyCodeObject,这个保存了函数的代码 PyFunctionObject,这个代表一个虚拟机 ...

  5. hive源码之新建一个coroutine

    最近由于项目需要读了一下云风老大的hive项目代码,因为对lua只有熟悉的水平,下面的东西必然多多错误:),只为记录. lua_State *sL = schedule_newtask(L); str ...

  6. Lua Coroutine详解

    协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈,局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.线程与协同程序的主要区别在于,一个具有多线程的程序可以同时运行几个线程 ...

  7. 【Unity3D基础教程】给初学者看的Unity教程(五):详解Unity3D中的协程(Coroutine)

    作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 为什么需要协程 在游戏中有许多过程(Proc ...

  8. Lua 协程coroutine

    协程和一般多线程的区别是,一般多线程由系统决定该哪个线程执行,是抢占式的,而协程是由每个线程自己决定自己什么时候不执行,并把执行权主动交给下一个线程. 协程是用户空间线程,操作系统其存在一无所知,所以 ...

  9. U3D中的 Coroutine程序 解析

    今天咱就说说协同程序coroutine. 什么是协同程序 先说说啥是协程:它的表现形式非常像线程,对线程有过接触的朋友可能更理解我这句话的意思,你没接触过线程,那么理解它会有一些难度.但是它不存在线程 ...

随机推荐

  1. Visual Studio 2010的MSDN帮助文档离线使用

    如果没有在安装vs过程中安装帮助,也可通过Visual Studio帮助菜单中的Manage Help Settings来对帮助进行设置或安装. 可以选择从磁盘安装内容,如果选择从磁盘安装可能会要求提 ...

  2. webapi - 使用依赖注入

    本篇将要和大家分享的是webapi中如何使用依赖注入,依赖注入这个东西在接口中常用,实际工作中也用的比较频繁,因此这里分享两种在api中依赖注入的方式Ninject和Unity:由于快过年这段时间打算 ...

  3. xamarin DependencyService源码阅读

    xamarin在面对PCL无法实现的各平台特有功能时使用了一种叫[DependencyService]的方式来实现.它使得xamarin能像原生平台一样做平台能做到的事情!主要分四个部分 接口:定义功 ...

  4. 【翻译】MongoDB指南/CRUD操作(四)

    [原文地址]https://docs.mongodb.com/manual/ CRUD操作(四) 1 查询方案(Query Plans) MongoDB 查询优化程序处理查询并且针对给定可利用的索引选 ...

  5. 手动添加kdump

    背景:     Linux嵌入式设备内核挂死后,无法自动重启,需要手动重启.而且如果当时没有连串口的话,就无法记录内核挂死时的堆栈,所以需要添加一种方式来记录内核挂死信息方便以后调试使用.设备中增加k ...

  6. 步入angularjs directive(指令)--准备工作熟悉hasOwnProperty

    在讲解directive之前,先做一下准备工作,为何要这样呢? 因为我们不是简单的说说directive怎么用,还要知道为什么这么用!(今天我们先磨磨刀!). 首先我们讲讲js 基础的知识--hasO ...

  7. 【Reading Note】算法读书杂记

    1 排序 排序基本信息 稳定性:排序前大的数在排序后,大的数依然保持不变就是稳定排序,反之不稳定 内外排序:根据待排序的记录是否放在内存里面区分的.诸如:插入排序(直接插入&希尔).交换排序( ...

  8. yaf的简单入门

    1.目录结构: 2.入口文件 入口文件是所有请求的入口,一般都借助于rewrite规则,把所有的请求都重定向到这个入口文件. 一个经典的入口文件  public/index.php 3.重写规则 需要 ...

  9. 访问者模式(visitorpattern)

    /** * 访问者模式 * @author TMAC-J * 在客户端和元素之间添加一个访问者 * 当你需要添加一些和元素关系不大的需求时,可以直接放在访问者里面 * 或者是元素之间有一些公共的代码块 ...

  10. 最近在玩linux时 yum 遇到了问题

    主要是软件源出现了问题 我做的方式可能比较粗暴 ls -l /etc/yum.repos.d/       /*查看软件源*/ rm -rf /etc/yum.repos.d/   /*全删了*/ m ...