跳到主要内容
信息
· 文章中可能会出现一些错误,希望大佬们可以在评论区指出;

12-协程

协程和线程类似,协程是一系列的可执行语句,拥有自己的栈、局部变量和指令指针,同时协程又与其他协程共享了全局变量和其他几乎一切资源;线程与协程的区别在于,一个多线程程序可以并行运行多个线程,而协程需要彼此协作运行,即在任意指定的时刻只能有一个协程运行,且只有当正在运行的协程显式要求被挂起时其执行才会暂停。

基本操作​

创建协程​

主要通过如下函数创建一个协程:

  • coroutine.create(func):创建一个新协程,参数为包含要执行代码的函数(通常为匿名函数),返回thread类型的新协程。
    co = coroutine.create(function ()
    print("Hi")
    end)
    print(type(co)) --> thread

  • coroutine.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, 7
    end)

    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 hi
    coroutine.resume(co, 3, 4) --> co2 3 4

此外,对于通过coroutine.wrap()创建的协程,返回值就是coroutine.resume()的第二部分。

参考资料​