ngin Finding Everything About Nginx Here

lua协程和异步

发表于 2015-06-19 阅读数 2675

1、缘起

我最早接触协程时,对这东西很费解,甚至我看了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的前辈云风的 BLOG: Lua 5.2 如何实现 C 调用中的 Continuation


本文结束!