【深入Lua】理解Lua中最强大的特性-coroutine(协程)
点击进入我的新博客 ###coroutine基础 Lua所支持的协程全称被称作协同式多线程(collaborative multithreading)。Lua为每个coroutine提供一个独立的运行线路。然而和多线程不同的地方就是,coroutine只有在显式调用yield函数后才被挂起,同一时间内只有一个协程正在运行。 Lua将它的协程函数都放进了coroutine这个表里,其中主要的函数如下 摘取一段云风的代码来详尽解释协程的工作机制,在这段代码中,展示了main thread和协程co之间的交互: <!-- lang: lua --> function foo(a) print("foo",a) return coroutine.yield(2 * a) end co = coroutine.create(function ( a,b ) print("co-body",a,b) local r = foo(a + 1) print("co-body",r) local r,s = coroutine.yield(a + b,a - b) print("co-body",r,s) return b,"end" end) print("main",coroutine.resume(co,1,10)) print("main","r")) print("main","x","y")) print("main","y")) 下面是运行结果 co-body 1 10 foo 2 main true 4 co-body r main true 11,-9 co-body x y main false 10 end main false cannot resume dead coroutine ###coroutine和subroutine(子例程)的比较 子例程的起始处是唯一的入口点,一旦return就完成了子程序的执行,子程序的一个实例只会运行一次。 但是协程不一样,协程可以使用yield来切换到其他协程,然后再通过resume方法重入**(reenter)到上次调用yield的地方,并且把resume的参数当成返回值传给了要重入(reenter)**的协程。但是coroutine的状态都没有被改变, 协程的精妙之处就在于 var q = queue() 生产者的伪码 loop while q is not full create product add the items to q resume to consumer 消费者的伪码 loop while q is not empty consume product remove the items from q yield ###coroutine的和callback的比较 coroutine经常被用来和callback进行比较,因为通常来说,coroutine和callback可以实现相同的功能,即异步通信,比如说下面的这个例子: <!-- lang: lua --> bob.walkto(jane) bob.say("hello") jane.say("hello") 看起来好像是对的,但实际上由于这几个动作walkto,say都是 如果使用回调来实现的话,代码示例如下: <!-- lang: lua --> bob.walto(function ( ) bob.say(function ( ) jane.say("hello") end,"hello") end,jane) 即walto函数回调say函数,say函数再回调下一个say函数,这样回调看起来十分混乱,让人无法一下看出这段代码的意义. 如果用coroutine的话,可以使用如下写法: <!-- lang: lua --> co = coroutine.create(function ( ) local current = coroutine.running bob.walto(function ( ) coroutine.resume(current) end,jane) coroutine.yield() bob.say(function ( ) coroutine.resume(current) end,"hello") coroutine.yield() jane.say("hello") end) coroutine.resume(co) 在上述代码中,一旦一个异步函数被调用,协程就会使用coroutine.yield()方法将该协程暂时悬挂起来,在相应的回调函数中加上coroutine.resume(current),使其返回目前正在执行的协程中。 但是,上述代码中有许多重复的地方,所以可以通过将封装的方式将重复代码封装起来 <!-- lang: lua --> function runAsyncFunc( func,... ) local current = coroutine.running func(function ( ) coroutine.resume(current) end,...) coroutine.yield() end coroutine.create(function ( ) runAsyncFunc(bob.walkto,jane) runAsyncFunc(bob.say,"hello") jane.say("hello") end) coroutine.resume(co) 这样就不需要改变从前的所有回调函数,即可通过携程的方式解决异步调用的问题,使得代码的结构非常清晰。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |