Lua 協(xié)同程序(coroutine)與線程比較類似:擁有獨(dú)立的堆棧,獨(dú)立的局部變量,獨(dú)立的指令指針,同時又與其它協(xié)同程序共享全局變量和其它大部分東西。
協(xié)同是非常強(qiáng)大的功能,但是用起來也很復(fù)雜。
線程與協(xié)同程序的主要區(qū)別在于,一個具有多個線程的程序可以同時運(yùn)行幾個線程,而協(xié)同程序卻需要彼此協(xié)作的運(yùn)行。
在任一指定時刻只有一個協(xié)同程序在運(yùn)行,并且這個正在運(yùn)行的協(xié)同程序只有在明確的被要求掛起的時候才會被掛起。
協(xié)同程序有點(diǎn)類似同步的多線程,在等待同一個線程鎖的幾個線程有點(diǎn)類似協(xié)同。
方法 | 描述 |
---|---|
coroutine.create() | 創(chuàng)建coroutine,返回coroutine, 參數(shù)是一個函數(shù),當(dāng)和resume配合使用的時候就喚醒函數(shù)調(diào)用 |
coroutine.resume() | 重啟coroutine,和create配合使用 |
coroutine.yield() | 掛起coroutine,將coroutine設(shè)置為掛起狀態(tài),這個和resume配合使用能有很多有用的效果 |
coroutine.status() | 查看coroutine的狀態(tài) 注:coroutine的狀態(tài)有三種:dead,suspend,running,具體什么時候有這樣的狀態(tài)請參考下面的程序 |
coroutine.wrap() | 創(chuàng)建coroutine,返回一個函數(shù),一旦你調(diào)用這個函數(shù),就進(jìn)入coroutine,和create功能重復(fù) |
coroutine.running() | 返回正在跑的coroutine,一個coroutine就是一個線程,當(dāng)使用running的時候,就是返回一個corouting的線程號 |
-- 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()) --nil print("----------")
以上實(shí)例執(zhí)行輸出結(jié)果為:
1 dead ---------- 1 ---------- 1 2 3 running thread: 0x7fb801c05868 false suspended thread: 0x7fb801c04c88 true ----------
coroutine.running就可以看出來,coroutine在底層實(shí)現(xiàn)就是一個線程。
當(dāng)create一個coroutine的時候就是在新線程中注冊了一個事件。
當(dāng)使用resume觸發(fā)事件的時候,create的coroutine函數(shù)就被執(zhí)行了,當(dāng)遇到y(tǒng)ield的時候就代表掛起當(dāng)前線程,等候再次resume觸發(fā)事件。
接下來我們分析一個更詳細(xì)的實(shí)例:
function foo (a) print("foo 函數(shù)輸出", a) return coroutine.yield(2 * a) -- 返回 2*a 的值 end co = coroutine.create(function (a , b) print("第一次協(xié)同程序執(zhí)行輸出", a, b) -- co-body 1 10 local r = foo(a + 1) print("第二次協(xié)同程序執(zhí)行輸出", r) local r, s = coroutine.yield(a + b, a - b) -- a,b的值為第一次調(diào)用協(xié)同程序時傳入 print("第三次協(xié)同程序執(zhí)行輸出", r, s) return b, "結(jié)束協(xié)同程序" -- b的值為第二次調(diào)用協(xié)同程序時傳入 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("---分割線---")
以上實(shí)例執(zhí)行輸出結(jié)果為:
第一次協(xié)同程序執(zhí)行輸出 1 10 foo 函數(shù)輸出 2 main true 4 --分割線---- 第二次協(xié)同程序執(zhí)行輸出 r main true 11 -9 ---分割線--- 第三次協(xié)同程序執(zhí)行輸出 x y main true 10 結(jié)束協(xié)同程序 ---分割線--- main false cannot resume dead coroutine ---分割線---
以上實(shí)例接下如下:
resume和yield的配合強(qiáng)大之處在于,resume處于主程中,它將外部狀態(tài)(數(shù)據(jù))傳入到協(xié)同程序內(nèi)部;而yield則將內(nèi)部的狀態(tài)(數(shù)據(jù))返回到主程中。
現(xiàn)在我就使用Lua的協(xié)同程序來完成生產(chǎn)者-消費(fèi)者這一經(jīng)典問題。
local newProductor function productor() local i = 0 while true do i = i + 1 send(i) -- 將生產(chǎn)的物品發(fā)送給消費(fèi)者 end end function consumer() while true do local i = receive() -- 從生產(chǎn)者那里得到物品 print(i) end end function receive() local status, value = coroutine.resume(newProductor) return value end function send(x) coroutine.yield(x) -- x表示需要發(fā)送的值,值返回以后,就掛起該協(xié)同程序 end -- 啟動程序 newProductor = coroutine.create(productor) consumer()
以上實(shí)例執(zhí)行輸出結(jié)果為:
1 2 3 4 5 6 7 8 9 10 11 12 13 ……
更多建議: