什么是协程?
从多线程的角度来看,协程类似于线程:协程是一系列可执行语句,有自己的栈、局部变量和指令指针,协程与其他协程通信。进程共享全局变量和几乎所有其他内容。
线程和协程的主要区别:
一个多线程程序可以同时并行运行多个线程,但是协程需要相互协同运行,即任何时候只能运行一个协程,协程的切换是手动控制的用户模式。只有当正在运行的协程的显式要求被挂起时,正在运行的协程的执行才会被挂起。
Lua 中的协程支持提供库函数
Lua中所有与协程相关的函数都放在协程表中。
注意:方括号是可选参数
函数原型函数补充
coroutine.create(function object) -> coroutine object
创建协程对象并返回
类型(协程对象)=线程
coroutine.resume(coroutine object, [parameters 1, 2, 3...] 传递给协程函数) -> state, value
开始/继续执行协程
正常执行:返回true和yield返回值;发生未捕获的错误:返回 false 和错误消息
coroutine.yield([返回值])
暂停当前运行的协程
coroutine.status(协程对象)->状态
返回协程状态
create和yield后,挂起(suspended);执行过程正在运行(running);执行完毕就死了(dead);唤醒A协程中的B协程,则A协程处于正常(normal)状态。
coroutine.wrap(协程体函数)->函数
创建一个新的协程,以传入的函数作为主函数并返回一个函数
返回函数和resume类似,不同的是调用不会返回状态,只返回值,如果发生错误3D交通工具,会抛出异常。
使用示例
如果我们需要计算并打印一个斐波那契数列,假设每一步计算需要一秒,传统的写法可以是这样的:
function Fibonacci(n)
local tab = {}
local a, b = 1, 1
for i = 1, n do
table.insert(tab, a)
local t = a + b
a = b
b = t
Sleep(1)
end
return tab
end
local fib = Fibonacci(10)
for i, v in ipairs(fib) do
io.write(v.." ")
end
运行结果:
1 1 2 3 5 8 13 21 34 55
运行过程:
等待 10 秒进行计算unity 协程和线程区别,然后立即打印所有结果。
计算过程卡住10秒显然不好。这个问题可以通过协程来优化。
协程计算可以这样写:
local coro = nil
function Fibonacci(n)
local a, b = 1, 1
for i = 1, n do
coroutine.yield(a) --挂起当前协程,并返回结果
local t = a + b
a = b
b = t
Sleep(1)
end
end
coro = coroutine.create(Fibonacci)
function GetFibonacciNext()
--开始/继续执行一个协程 正常执行:返回true和yield返回值 发生一个未捕获错误:返回false和错误信息
local state, value = coroutine.resume(coro, 10)
return value
end
for i = 1, 10 do
io.write(GetFibonacciNext().." ")
end
运行结果:
1 1 2 3 5 8 13 21 34 55
运行过程:
每计算一个结果(间隔1秒),立即返回并打印该值,直到打印10个序列项。
这种操作方式显然会更加友好,即在需要数据的时候进行计算。
使用协程作为迭代器
上面的遍历结果也可以改成迭代器的用法:
-- 把协程用作迭代器
function GetFibonacciNext(n)
local co = coroutine.create(Fibonacci)
return function()
local state, value = coroutine.resume(co, n)
return value
end
end
for v in GetFibonacciNext(10) do
io.write(v.." ")
end
这样写也能达到同样的效果,像迭代器一样用起来会更方便。
因为GetFibonacciNext的写法很常见unity 协程和线程区别硬件设备,唤醒对应协程的调用被包裹在一个函数中,所以Lua语言特地提供了一个函数coroutine.wrap来完成这个功能。 (上表详细介绍了wrap。)
使用 wrap 函数我们可以将 GetFibonacciNext 函数更改为以下代码:
function GetFibonacciNext(n)
return coroutine.wrap(function() Fibonacci(n) end)
end
效果是一样的。
参考:《Lua 编程》第 24 章