12-协程
协程和线程类似,协程是一系列的可执行语句,拥有自己的栈、局部变量和指令指针,同时协程又与其他协程共享了全局变量和其他几乎一切资源;线程与协程的区别在于,一个多线程程序可以并行运行多个线程,而协程需要彼此协作运行,即在任意指定的时刻只能有一个协程运行,且只有当正在运行的协程显式要求被挂起时其执行才会暂停。
基本操作
创建协程
主要通过如下函数创建一个协程:
coroutine.create(func):创建一个新协程,参数为包含要执行代码的函数(通常为匿名函数),返回thread类型的新协程。co = coroutine.create(function ()print("Hi")end)print(type(co)) --> threadcoroutine.wrap(func):创建一个新协程并返回可以运行该协程的函数,返回function类型的运行新协程的函数。co2 = coroutine.wrap(function ()print("Hello")end)print(type(co2))
协程的状态
协程共有四种状态:挂起(Suspended),运行(Running),正常(Normal)和死亡(Dead)。可通过函数coroutine.status(协程)检查一个协程的状态:
print(coroutine.status(co)) --> suspended
还能通过函数coroutine.running()获取当前正在运行的协程的线程号和一个布尔值,如果该协程为主线程则为真。
运行协程
被创建后的协程处于挂起状态,不会自动运行。函数coroutine.resume(协程 [, ...])用于(再次)启动一个协程的执行,并将它的状态从挂起更改为运行。如果该协程运行的函数有参数,可以将参数添加到协程参数后面:
coroutine.resume(co) --> Hi
-- 对于通过coroutine.wrap()创建的协程,直接运行它返回的函数即可
co2() --> Hello
协程运行完毕后会变成死亡状态:
print(coroutine.status(co)) --> dead
挂起协程
协程的真正强大之处在于函数coroutine.yield(),该函数可以让一个运行中的协程挂起自己,然后在后续恢复运行:
-- 使用coroutine.wrap()创建的协程同理
local co3 = coroutine.create(function ()
for i = 1, 3 do
print("running " .. i)
coroutine.yield()
end
end)
coroutine.resume(co3) --> running 1
coroutine.resume(co3) --> running 2
coroutine.resume(co3) --> running 3
print(coroutine.status(co3)) --> suspended
coroutine.resume(co3) -- 结束循环
print(coroutine.status(co3)) --> dead
在上述代码中,协程被唤醒后进入循环并输出running 1,输出后遇到coroutine.yield()进入挂起状态,再次被唤醒后才继续输出running 2,直至循环结束协程进入死亡状态。
协程间的通信
协程间也是可以通信的,例如当协程A唤醒协程B时,协程A从运行状态进入正常状态,协程B从挂起状态进入运行状态。
resume-yield 通信机制
coroutine.resume()可以和coroutine.yield()相互通信,这需要借助各自的参数和返回值:
- 对于还能运行的协程,
coroutine.resume()函数的返回值有两部分,协程是否运行成功的Boolean类型和coroutine.yield()函数内的参数:local co = coroutine.create(function (a, b)coroutine.yield(a + b, a - b)end)print(coroutine.resume(co, 20, 10)) --> true 30 10 - 对于运行结束时的协程,
coroutine.resume()函数的返回值的第二部分为主函数的返回值(如果有的话):local co = coroutine.create(function ()return 6, 7end)print(coroutine.resume(co)) -- > true 6 7 coroutine.yield()函数的返回值是对应coroutine.resume()函数内的参数:co = coroutine.create(function (x)print("co1", x)print("co2", coroutine.yield())end)coroutine.resume(co, "hi") --> co1 hicoroutine.resume(co, 3, 4) --> co2 3 4
此外,对于通过coroutine.wrap()创建的协程,返回值就是coroutine.resume()的第二部分。
参考资料
- 《Lua程序设计 (第4版)》
- 【唐老狮】Unity热更新之Lua语法