1、协程概念
协程是非抢断式的多线程方式,看上去像多线程,其实如同名字说的—协程,在协调多段程序的运行并且各自的代码段是有自己独立的变量的cache。本文主要通过实例将协程的处理讲清楚。 resume和yield是一个很好的桥梁,将代码段之间方便的传输参数。
2、协程的接口函数
函数 | 参数 | 说明 |
coroutine.create | f | 创建协程 |
coroutine.resume | co [, val1, ···] | 开启或者继续一个协程 |
coroutine.running | 无 | 返回是否协程在运行,或者返回nil当被主线程调用时 |
coroutine.status | co | 返回协程状态:running,suspended,normal,dead |
coroutine.wrap | co | 原生态创建协程 |
coroutine.yield | … | 挂起正在执行的 |
3、需要注意的点
coroutine.wrap类似coroutine.create , coroutine.wrap 这个函数也将创建一个 coroutine ,但是它并不返回 coroutine 本身,而是返回一个函数取而代之。一旦你调用这个返回函数,就会切入coroutine 运行。所有传入这个函数的参数等同于传入 coroutine.resume 的参数。 coroutine.wrap 会返回所有应该由除第一个(错误代码的那个布尔量)之外的由coroutine.resume 返回的值。和 coroutine.resume 不同, coroutine.wrap 不捕获任何错误;所有的错误都应该由调用者自己传递。
4、官方实例
(a)
print
coroutine.yield(
2*a)
co =
.create(function ("co-body", a, b)
local
(
"co-body", r)
local
(
"co-body", r, s)
return
end)
printcoroutine
print(
"main",
.resume(co,
"r"))
coroutine
print(
"main",
.resume(co,
"x",
"y"))
5、调用时序图
6、输出结果
>lua -e
"io.stdout:setvbuf 'no'"
"test.lua"
foo
2
trueco-body r
main
11 -
9
main
10
main
cannot resume dead
7、分析过程
主线程主线程协程协程resume(co, 1, 10) 主线程挂起,唤起协程foo (1+1)coroutine.yield(2*2) 协程挂起,主线程唤醒return resume()->主线程获得2*2返回值coroutine.resume(co, "r")主线程挂起,唤起协程localr = foo(a+1)触发resume("r")参数赋值给local rcoroutine.yield(a+b, a-b)协程挂起,主线程唤醒,将会1+10,1-10print("main",coroutine.resume(co, "r"))将yield的参数输出coroutine.resume(co, "x", "y")主线程挂起,唤起协程localr, s = coroutine.yield(a+b, a-b)主线程中输入的"x","y"变量将会被赋值给r,s由于协程已经执行全部的流程最终将会把流程交回给主线程,协程将会变成dead态print("main", coroutine.resume(co, "x","y"))将会触发协程函数返回值的打印X,协程已经不再工作状态,所以造成程序直接返回,服务器不能唤起。
看完这个例子之后,其实可以看出来这两个线程其实一直在配合做事情。当resume被调用的时候,主线程就暂停了活动,将运行的权限交给了coroutine来做事。当coroutine yield的时候,将会直接触发自己的coroutine暂停,激活主线程的resume的return,接着做事。所以理论上对一个coroutine的调用,函数中有几个yield,主线程的代码中需要些多少个resume函数,否则如果主线程只对coroutine做一次resume。但是这个也不会造成太多的内存问题,协程对象被释放掉之后也将不会存在内存泄露。