Lua 協同程序(coroutine)
什么是協同(coroutine)?

Lua 協同程序(coroutine)與線程比較類似:擁有獨立的堆棧,獨立的局部變量,獨立的指令指針,同時又與其它協同程序共享全局變量和其它大部分東西。
協同是非常強大的功能,但是用起來也很復雜。
線程和協同程序區別
線程與協同程序的主要區別在于,一個具有多個線程的程序可以同時運行幾個線程,而協同程序卻需要彼此協作的運行。
在任一指定時刻只有一個協同程序在運行,并且這個正在運行的協同程序只有在明確的被要求掛起的時候才會被掛起。
協同程序有點類似同步的多線程,在等待同一個線程鎖的幾個線程有點類似協同。
基本語法
以下實例演示了以上各個方法的用法:
coroutine_test.lua 文件
-- coroutine_test.lua 文件
co?=?coroutine.create(
function(i)
print(i);
end
)
coroutine.resume(co,?1)???-- 1
print(coroutine.status(co))??-- dead
print("----------")
co?=?coroutine.wrap(
function(i)
print(i);
end
)
co(1)
print("----------")
co2?=?coroutine.create(
function()
for?i=1,10?do
print(i)
if?i?==?3?then
print(coroutine.status(co2))??--running
print(coroutine.running())?--thread:XXXXXX
end
coroutine.yield()
end
end
)
coroutine.resume(co2)?--1
coroutine.resume(co2)?--2
coroutine.resume(co2)?--3
print(coroutine.status(co2))???-- suspended
print(coroutine.running())
print("----------")
以上實例執行輸出結果為:
1 dead ---------- 1 ---------- 1 2 3 running thread: 0x7fb801c05868 false suspended thread: 0x7fb801c04c88 true ----------
coroutine.running就可以看出來,coroutine在底層實現就是一個線程。
當create一個coroutine的時候就是在新線程中注冊了一個事件。
當使用resume觸發事件的時候,create的coroutine函數就被執行了,當遇到yield的時候就代表掛起當前線程,等候再次resume觸發事件。
接下來我們分析一個更詳細的實例:
實例
function?foo?(a)
print("foo 函數輸出",?a)
return?coroutine.yield(2?*?a)?-- 返回 ?2*a 的值
end
co?=?coroutine.create(function?(a?,?b)
print("第一次協同程序執行輸出",?a,?b)?-- co-body 1 10
local?r?=?foo(a?+?1)
print("第二次協同程序執行輸出",?r)
local?r,?s?=?coroutine.yield(a?+?b,?a?-?b)??-- a,b的值為第一次調用協同程序時傳入
print("第三次協同程序執行輸出",?r,?s)
return?b,?"結束協同程序"?? ? ? ? ? ? ? ? ??-- b的值為第二次調用協同程序時傳入
end)
print("main",?coroutine.resume(co,?1,?10))?-- true, 4
print("--分割線----")
print("main",?coroutine.resume(co,?"r"))?-- true 11 -9
print("---分割線---")
print("main",?coroutine.resume(co,?"x",?"y"))?-- true 10 end
print("---分割線---")
print("main",?coroutine.resume(co,?"x",?"y"))?-- cannot resume dead coroutine
print("---分割線---")
以上實例執行輸出結果為:
第一次協同程序執行輸出 1 10 foo 函數輸出 2 main true 4 --分割線---- 第二次協同程序執行輸出 r main true 11 -9 ---分割線--- 第三次協同程序執行輸出 x y main true 10 結束協同程序 ---分割線--- main false cannot resume dead coroutine ---分割線---
以上實例接下如下:
調用resume,將協同程序喚醒,resume操作成功返回true,否則返回false;
協同程序運行;
運行到yield語句;
yield掛起協同程序,第一次resume返回;(注意:此處yield返回,參數是resume的參數)
第二次resume,再次喚醒協同程序;(注意:此處resume的參數中,除了第一個參數,剩下的參數將作為yield的參數)
yield返回;
協同程序繼續運行;
如果使用的協同程序繼續運行完成后繼續調用 resume方法則輸出:cannot resume dead coroutine
resume和yield的配合強大之處在于,resume處于主程中,它將外部狀態(數據)傳入到協同程序內部;而yield則將內部的狀態(數據)返回到主程中。
生產者-消費者問題
現在我就使用Lua的協同程序來完成生產者-消費者這一經典問題。
實例
local?newProductor
function?productor()
local?i?=?0
while?true?do
i?=?i?+?1
send(i)?? ??-- 將生產的物品發送給消費者
end
end
function?consumer()
while?true?do
local?i?=?receive()?? ??-- 從生產者那里得到物品
print(i)
end
end
function?receive()
local?status,?value?=?coroutine.resume(newProductor)
return?value
end
function?send(x)
coroutine.yield(x)?? ??-- x表示需要發送的值,值返回以后,就掛起該協同程序
end
-- 啟動程序
newProductor?=?coroutine.create(productor)
consumer()
以上實例執行輸出結果為:
1 2 3 4 5 6 7 8 9 10 11 12 13 ……
Lua 任務調度
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。