Lua 创建和使用协程
示例
与协程互动的所有功能在协程表中都可用。通过使用带有单个参数的coroutine.create函数来创建新的协程:一个具有要执行的代码的函数:
thread1 = coroutine.create(function() print("honk") end) print(thread1) -->> thread: 6b028b8c
协程对象返回代表新协程的thread类型的值。创建新的协程时,其初始状态将被暂停:
print(coroutine.status(thread1)) -->> suspended
要恢复或启动协程,函数和coroutine.resume时,给定的第一个参数是线程对象:
coroutine.resume(thread1) -->> honk
现在协程执行代码并终止,将其状态更改为dead,至此无法恢复。
print(coroutine.status(thread1)) -->> dead
Coroutinescansuspenditsexecutionandresumeitlaterthankstothecoroutine.yieldfunction:
thread2 = coroutine.create(function() for n = 1, 5 do print("honk "..n) coroutine.yield() end end)
Asyoucansee,coroutine.yield()ispresentinsidetheforloop,nowwhenweresumethecoroutine,itwillexecutethecodeuntilitreachsacoroutine.yield:
coroutine.resume(thread2) -->> honk 1 coroutine.resume(thread2) -->> honk 2
Afterfinishingtheloop,thethreadstatusbecomesdeadandcannotberesumed.Coroutinesalsoallowstheexchangebetweendata:
thread3 = coroutine.create(function(complement) print("honk "..complement) coroutine.yield() print("再次鸣喇叭 "..complement) end) coroutine.resume(thread3, "stackoverflow") -->> honk stackoverflow
Ifthecoroutineisexecutedagainwithnoextraarguments,thecomplementwillstill theargumentfromthefirstresume,inthiscase"stackoverflow":
coroutine.resume(thread3) -->> 再次鸣喇叭 stackoverflow
Finally,whenacoroutineends,anyvaluesreturnedbyitsfunctiongotothecorrespondingresume:
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
Coroutinesareusedinthisfunctiontopassvaluesbacktoacallingthreadfromdeepwithinarecursivecall.
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的作者RobertoIerusalimschy也发表了一篇论文,内容涉及使用协程来实现更高级的通用流程控制机制,例如延续。