创建并使用协程
在协同程序表中可以使用与协同程序交互的所有功能。通过使用带有单个参数的 coroutine.create 函数创建一个新的协程 :一个带有要执行的代码的函数:
thread1 = coroutine.create(function()
print("honk")
end)
print(thread1)
-->> thread: 6b028b8c
一个 coroutine 对象返回 thread 类型的值,表示一个新的 coroutine。创建新协程时,其初始状态将被暂停:
print(coroutine.status(thread1))
-->> suspended
要恢复或启动协程,使用函数 coroutine.resume ,给出的第一个参数是线程对象:
coroutine.resume(thread1)
-->> honk
现在协程执行代码并终止,将其状态更改为 dead ,无法恢复。
print(coroutine.status(thread1))
-->> dead
由于 coroutine.yield 函数,协同程序可以暂停其执行并在以后恢复它 :
thread2 = coroutine.create(function()
for n = 1, 5 do
print("honk "..n)
coroutine.yield()
end
end)
如你所见,coroutine.yield()
存在于 for 循环中,现在当我们恢复协程时,它将执行代码,直到它到达 coroutine.yield:
coroutine.resume(thread2)
-->> honk 1
coroutine.resume(thread2)
-->> honk 2
在完成循环后,线程状态变成死,不能恢复。协同程序还允许数据之间的交换:
thread3 = coroutine.create(function(complement)
print("honk "..complement)
coroutine.yield()
print("honk again "..complement)
end)
coroutine.resume(thread3, "stackoverflow")
-->> honk stackoverflow
如果在没有额外参数的情况下再次执行协程,则补码仍将是第一个简历中的参数,在本例中为 stackoverflow
:
coroutine.resume(thread3)
-->> honk again stackoverflow
最后,当一个协程结束时,其函数返回的任何值都会转到相应的简历:
thread4 = coroutine.create(function(a, b)
local c = a+b
coroutine.yield()
return c
end)
coroutine.resume(thread4, 1, 2)
print(coroutine.resume(thread4))
-->> true, 3
协程在此函数中用于在递归调用中从深处将值传递回调用线程。
local function Combinations(l, r)
local ll = #l
r = r or ll
local sel = {}
local function rhelper(depth, last)
depth = depth or 1
last = last or 1
if depth > r then
coroutine.yield(sel)
else
for i = last, ll - (r - depth) do
sel[depth] = l[i]
rhelper(depth+1, i+1)
end
end
end
return coroutine.wrap(rhelper)
end
for v in Combinations({1, 2, 3}, 2) do
print("{"..table.concat(v, ", ").."}")
end
--> {1, 2}
--> {1, 3}
--> {2, 3}
协同程序也可用于惰性评估。
-- slices a generator 'c' taking every 'step'th output from the generator
-- starting at the 'start'th output to the 'stop'th output
function slice(c, start, step, stop)
local _
return coroutine.wrap(function()
for i = 1, start-1 do
_ = c()
end
for i = start, stop do
if (i - start) % step == 0 then
coroutine.yield(c())
else
_ = c()
end
end
end)
end
local alphabet = {}
for c = string.byte('a'), string.byte('z') do
alphabet[#alphabet+1] = string.char(c)
end
-- only yields combinations 100 through 102
-- requires evaluating the first 100 combinations, but not the next 5311633
local s = slice(Combinations(alphabet, 10), 100, 1, 102)
for i in s do
print(table.concat(i))
end
--> abcdefghpr
--> abcdefghps
--> abcdefghpt
协同程序可用于管道构造,如在 Lua 编程中所述。PiL 的作者 Roberto Ierusalimschy 也发表了一篇关于使用协程来实现更先进和一般流控制机制(如延续)的论文。