协程与线程
同
协程是一系列的可执行语句,拥有自己的栈、局部变量和指令指针,同时协程又与其他协程共享了全局变量和其他几乎一切资源。
异
一个多线程程序可以并行运行多个线程,而协程却需要彼此协作地运行,即在任意指定的时刻只能有一个协程运行,且只有当正在运行的协程显式地要求被挂起时其执行才会暂停。
协程基础
Lua语言中协程相关的所有函数都被放在表coroutine中。
协程创建
函数create
用于创建新协程,该函数只有一个参数,即协程要执行的代码的函(协程体)。
函数create
返回一个"thread"
类型的值,即新协程。通常,函数create
的参数是一个匿名函数
co = coroutine.create(function() print( "hi" ) end)
print(type(co)) --> thread
协程状态
一个协程有以下四种状态,即挂起(suspended)、运行(running)、正常(normal)和死亡(dead)。
我们可以通过函数coroutine.status来检查协程的状态:
print(coroutine.status(co)) --> suspended
协程启动
函数coroutine.resume
用于启动或再次启动一个协程的执行,并将其状态由挂起改为运行:
coroutine.resume(co) --> hi
在最后一行加上一个分号来阻止输出函数resume的返回值。在上例中,协程体只是简单地打印了"hi"后便终止了,然后协程就变成了死亡状态:
print(coroutine.status(co)) --> dead
函数yield
可以让一个运行中的协程挂起自己,然后在后续恢复运行
co = coroutine.create(function ()
for i = 1, 10 do
print("co", i)
coroutine.yield()
end
end)
其中,协程进行了一个循环,在循环中输出数字并在每次打印后挂起。当唤醒协程后,它就会开始执行直到遇到第一个yield:
coroutine.resume(co) --> co 1
此时,查看协程状态,会发现协程处于挂起状态,因此可以再次恢复运行:
coroutine.status(co) --> suspended
当我们唤醒协程时,函数yield才会最终返回,然后协程会继续执行直到遇到下一个yield或执行结束:
coroutine.resume(co) -->co 2 coroutine.resume(co) -->co 3 ... coroutine.resume(co) -->co 10 coroutine.resume(co) -->不输出任何数据
再次调用会输出错误信息
coroutine.status(co) --> false cannot resume dead coroutine
当协程A唤醒协程B时,协程A既不是挂起状态(因为不能唤醒协程A),也不是运行状态(因为正在运行的协程是B)。所以,协程A此时的状态就被称为正常状态。
resume-yield机制
通过一对resume-yield来交换数据。第一个resume 函数(没有对应等待它的yield)会把所有的额外参数传递给协程的主函数:
co = coroutine. create(function (a, b, c)
print("co", a, b, c + 2)
end)
coroutine.resume(co,1,2,3) -->co 1 2 5
在函数coroutine.resume
的返回值中,第一个返回值为true时表示没有错误,之后的返回值对应函数yield的参数:
co = coroutine.create(function (a, b)
coroutine.yield(a + b, a - b)
end)
print(coroutine.resume( co,20,10)) --> true 30 10
函数coroutine.yield
的返回值是对应的resume
的参数:
co =coroutine.create(function (x)
print("co1", x)
print("co2", coroutine.yield())
end)
coroutine.resume(co, "hi") --> co1 hi
coroutine.resume(co,4, 5) --> co2 4 5
当一个协程运行结束时,主函数所返回的值都将变成对应函数resume
的返回值:
co = coroutine.create(function ()
return 6,7
end)
print(coroutine.resume(co)) --> true 6 7