在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
前言
Tip1:扩展阅读必读 Tip2:明白了yield和resume之间的切换和参数传递,也就明白了协程。 Tip3:必读资料 http://manual.luaer.cn/2.11.html http://pgl.yoyo.org/luai/i/2.11+Coroutines 为什么会有协程? 在编程时,难免会遇到一些带有阻塞的流程,例如最简单的led闪烁 例1: main(){ while(1):{ led =1; delay_ms(1000); led = 0; delay_ms(1000); } } 面对这样的阻塞的状况,我们可以自己编写状态机,绕过这个阻塞。 //定时器,50ms void Timer0() { t_cnt ++; if(t_cnt>2000) t_cnt = 0; } main() { while(1) { switch(step) { case 0: if(t_cnt > 20) { led = 1; t_cnt = 0; step ++; } break; case 1: if(t_cnt > 20) { led = 0; t_cnt = 0; step --; } break; default: step = 0; break; }}} 这只是一个非阻塞的状态机模式的思路的展示,也可以使用if..else..编写。 在lua中编写非阻塞的流程控制也要像c一样自己搞状态机吗?不,lua中有现成的非阻塞编程框架:协程。
怎么使用协程? 协程就是使用resume唤醒coroutine,并传入参数,使用yield暂停coroutine(resume立刻return yield的参数) coroutine基本的语法和的几个函数要了解清楚,熟记于心,通过掌握这几个函数,会对协程的机制有更加清晰、细致的认识。 coroutine.create() 功能:新建一个协同程序 参数:唯一的参数是这个协程的主函数。 返回值:此协程的句柄(thread类型) 说明:创建后的协同程序状态为suspended挂起状态(另,running运行状态,dead死亡状态),并没有运行。 原文:
#例1:create的新协程:main function co = coroutine.create(function() print("hello,world") print("Goodbye,honey") end) coroutine.resume()功能:启动一个suspended挂起状态的协同程序 参数:协程的句柄,其他的参数会传递给协程 返回值:true(代表成功调用)+value(main function有返回值 or yield的参数 or nothing)/false+error message 说明:resume一个协程时,有两种方式结束(注意:不是暂停)其运行: 1、create中的function运行到最后(return或者最后一条指令) 2、运行中出现不可预料的错误 原文:
#例2:resume的参数传递 co = coroutine.create(function (a,b,c) print("co", a,b,c) end) coroutine.resume(co, 1, 2, 3) --> co 1 2 3 在coroutine.resume(co,1,2,3),传递co这个句柄,链接到了create内部的function(a,b,c),并且把参数1,2,3传递进去,接着print,就输出了 co 1 2 3 Q:什么时候协同程序会变成dead死亡状态呢? A:当coroutine.create内的main function执行完毕,它就dead了。如果还想使用,就再次create,然后使用resume激活执行。 coroutine.yield()功能:暂停协程 参数:参数就是给相应的resume的返回值value 返回值:true(代表成功调用)/false+error message 说明:执行到yield,会挂起当前协程,coroutine.resume立刻return true和yield的参数。不管这个yield是放在协程中,还是协程间接、直接调用的函数中。 原文:
最后一句话的翻译:下次使用resume唤醒协程时,会从之前暂停的点继续执行,resume会把自己额外的参数(即除了协程的句柄的其他参数)传递给yield语句(可理解为用resume的额外参数直接替换yield语句) #例2:yield和resume参数的传递 运行结果: co-body 1 10 foo 2 main true 4 co-body r main true 11 -9 co-body x y main true 10 end main false cannot resume dead coroutine 代码执行分析: step1:执行第一个print,出现resume,切换进入create的协程function中,打印出 co-body 1 10 step2:执行function中第二句(定义一个局部变量r并赋值),进入foo,打印出 foo 2 step3:执行foo中的第二句,return时遇到yield(foo中的这个return并没有得到执行,因为要先执行yield再return),协程正常暂停,此时resume函数立刻return一个true和 coroutine.yield(2*a)的参数 2*a(=4) step4:执行第一个print,打印出main true 4 step5:执行第二个print,程序从上次暂停的为止foo(a)中的return执行,且resume把参数(字符"r")传递给yield,则foo返回值为字符"r",赋值给local r step6:第二个print,则打印出 co-body r step7:执行 local r, s = coroutine.yield(a+b, a-b),协程正常暂停,此时resume函数立刻return 一个true和coroutine.yield(a+b,a-b)的参数a+b,a-b,打印出 main true 11 -9 step8:执行第三个print时,又遇到resume,从上次暂停的地方运行,resume把参数x,y传递给yield,则local r,s = x ,y,打印出 co-body x y step9:因为协程是正常执行到return,正常结束,resume返回true和协程中return的值 10 end。则第三个print,则打印出 main true 10 end coroutine.status()查看coroutine的状态 注:coroutine的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序 coroutine.wrap()功能:创建一个协程 参数:main function 返回值:协程的句柄 说明:使用wrap创建的协程在resume时,返回值不包含true和false,当然false时也不会返回error message。这样可以让程序清晰,但不会报错,会影响调试。每次使用wrap返回的函数,都相当于隐式调用了resume,唤醒了协程的main function。 原文:
例子: local f = coroutine.wrap( function(a,b) print(a,b) local x,y=coroutine.yield("yield") print(x,y) return ('bingo') end) print(f(1,2)) print(f(8,9)) --> 1 2 yield 8 9 bingo
coroutine.running()返回正在跑的coroutine,一个coroutine就是一个线程,当使用running的时候,就是返回一个coroutine的句柄
---------------------------------------------------------------------------------------------------------------------
|