我最早接触协程时,对这东西很费解,甚至我看了lua的协程源码实现后,这个疑虑还是没有消除。直到有次在需要用异步编程时,对协程的理解一下子明白了。所以希望用从异步的角度解释协程,能让您有跟我一样的收获。 2、写过的 我们的业务经常需要第三方服务打交道,比如db, nosql, http api等。这种交互要么是阻塞的,要么是异步的。 在nodejs里的异步处理方式: db.query('users', {name: name}, function(err, users) { deal_with(users); }); nodejs里处理异步很简单,注册个回调即可。编程世界是多元的,每种文化都非常优秀,往往思维的碰撞会产生一些有意思的方式。我们习惯用顺序的方式写代码,如果不关心这是阻塞或是异步就很理想了,只要语言保证性能足够好。 users = db.query('users', {name: name}); deal_with(users); 可能你会认为代码会阻塞在db.query,等有结果后才会去调用deal_with。那如果加入协程的概念后呢?一切变的很有意思。 3、什么是协程? 协程是一种特殊的函数,可以在执行的过程中随时暂时,随时继续执行。这是我的理解。 function foo() a(); b(); c(); end 我们知道当我们调用foo()时,直到函数有返回或终止时才会结束执行。但是如果foo是个协程(我说过协程是一个特殊的函数)。它可以在执行到a() 时,不继续执行,先返回。等你需要时继续调用,但下次是从上次暂停的位置继续执行,也就是从b开始。这里很重要的一点是协程的暂时不是阻塞,我们会继续讲 解。所以当我们把协程引入前面的db.query例子时,如果一切如我们所希望的,它就是同步的写法,异步的实现,谁悄悄做了手脚呢?服务器和协程。 4、nginx和lua的绝配 服务器有个设计原则:永远不能阻塞。nginx作为非常优秀的服务器,这点发挥的非常极致。在nginx里有很多的体现异步的地方。我们继续以上面的例子为例: function foo() // foo本身是个协程,由nginx调用 users = db.query('users', {name: name}); // 此处由nginx发起db的连接请求,因为异步这里先暂停协程 deal_with(users); // 当请求有响应得到处理时,继续执行协程,这些才运行 end 通过nginx的异步机制和lua的协程,很容易实现这种同步写法,异步实现的模型,但对开发人员而言,不用关心内部做了什么。 5、lua里如何实现协程 lua本身设计是c的胶体,除了可以写lua脚本语言代码,还可以用c调用lua的c接口。在协程这个地方也是如此。 既然上面提到nginx(c实现的),这里将列两种使用协程的方式: a、脚本语言里使用 co = coroutine.create(function () for i=1,10 do print("co", i) coroutine.yield() end end) coroutine.resume(co) // 输出 co 1 coroutine.resume(co) // 输出 co 2 coroutine.resume(co) // 输出 co 3 co是个协程,是个特殊的函数 coroutine.yield是暂停(挂起)协程 coroutine.resume是继续执行(唤醒)协程 b、c调用方式 参考国内研究lua的前辈的文章: Lua 5.2 如何实现 C 调用中的 Continuation 转载请保留固定链接: https://linuxeye.com/Linux/2610.html |