哎。周五晚上我都還這麼努力看書。真是好孩子。(小若:不想吐槽了)
事實上我都準備玩遊戲
看電影去的了。可是這書就擺在桌子
上。並且正對著我,就想著。掃兩眼吧。
結果一掃就不正確勁了,由於這內容有點繞,有點小混亂,假設我如今不記錄下來的話。下周一可能又要又一次看一次了。
好吧,今天我們來聊聊協同程式。
笨木頭花心貢獻,哈?花心?不,是用心~大家都知道執行緒吧?都知道多執行緒吧?協同程式就和這執行緒差點兒相同,可是又有比較明顯的區別。
多個協同程式在隨意時刻僅僅能執行乙個,儘管執行緒在某種意義上也是這樣,但這不是一樣的概念。
換句話說,乙個協同程式在執行的時候。其它協同程式是無法獲得執行的機會的。
僅僅有正在執行的協同程式主動掛起時,其它協同程式才有機會執行。
而執行緒呢?即使不主動休眠。也非常有可能由於輪片時間到達而把執行機會讓給其它執行緒。
建立協同程式非常easy。咋一看。事實上和執行緒沒區別~
**例如以下:
local co = coroutine.create(function() print("hello coroutine"); end);協同的程式的操作都在coroutine裡,create函式的引數就是協同程式要執行的函式,就這麼執行**是沒有效果的。
由於協同程式建立後,預設是掛起狀態。
協同程式的四種狀態分別為:掛起(suspended)、執行(running)、死亡(dead)、正常(normal)。
要想協同程式執行起來,就要呼叫resume函式。
例如以下**:
local co = coroutine.create(function() print("hello coroutine"); end);coroutine.resume(co);
輸出結果例如以下:
[lua-print] hello coroutine
剛剛那個協同程式太簡陋的。沒有不論什麼作用,直接列印
一條語句之後就結束了,同一時候它的狀態也變成了死亡狀態。
我們來乙個帥一點的協同程式:
local co = coroutine.create(function()for i = 1, 2, 1 do
print("木頭挺聰明的+" .. i);
endend);
coroutine.resume(co);
執行結果例如以下:
[lua-print] 木頭挺聰明的+1
[lua-print] 木頭挺聰明的+2
所以我就說,電腦就是誠實。這日誌列印的,真好看(小若:我們不要理這個神經病了)
既然協同程式和執行緒差點兒相同。那肯定不能讓協同程式一次過執行完成了,這就沒有意義了。
我們來看看怎麼讓協同程式掛起,例如以下**:
local co = coroutine.create(function()for i = 1, 2, 1 do
print("木頭挺聰明的+" .. i);
coroutine.yield();
endend);
coroutine.resume(co);
print(coroutine.status(co));
輸出結果例如以下:
[lua-print] 木頭挺聰明的+1
[lua-print] suspended
這回就僅僅輸出了一條日誌就停止了,後面我們還呼叫了status函式,列印協同程式當前的狀態,suspended即為掛起狀態。
由於這個協同程式還沒有執行完成。所以僅僅能是掛起狀態。
那麼,假設讓這協同程式繼續執行呢?非常easy,再次呼叫resume函式。如**:
local co = coroutine.create(function()for i = 1, 2, 1 do
print("木頭挺聰明的+" .. i);
coroutine.yield();
endend);
coroutine.resume(co);
print(coroutine.status(co));
coroutine.resume(co);
print(coroutine.status(co));
coroutine.resume(co);
print(coroutine.status(co));
這次有點複雜了。先看看輸出結果:
[lua-print] 木頭挺聰明的+1
[lua-print] suspended
[lua-print] 木頭挺聰明的+2
[lua-print] suspended
[lua-print] dead
我一共執行了三次resume函式。但非常顯然,這個協同程式的for迴圈僅僅會執行2次。
那為什麼第二次resume執行之後,協同程式的狀態還是掛起呢?不應該是結束了麼?結束了就應該是死亡狀態了。
而第三次執行resume之後,反而沒有不論什麼輸出,此時的狀態才真正切換到死亡狀態。
這是為什麼呢?(小若:趕緊說,不說我看電影去了)
再來這麼看看就明確了。加幾條列印
**:
local co = coroutine.create(function()for i = 1, 2, 1 do
print("木頭挺聰明的+" .. i);
coroutine.yield();
print("一次迴圈結束");
endprint("協同
程式結束");
end);
coroutine.resume(co);
print(coroutine.status(co));
coroutine.resume(co);
print(coroutine.status(co));
coroutine.resume(co);
print(coroutine.status(co));
輸出結果例如以下:
[lua-print] 木頭挺聰明的+1
[lua-print] suspended
[lua-print] 一次迴圈結束
[lua-print] 木頭挺聰明的+2
[lua-print] suspended
[lua-print] 一次迴圈結束
[lua-print] 協同
程式結束
[lua-print] dead
這就非常明顯了,在協同程式裡呼叫yield函式時。會被掛起,而yield函式的返回要等下一次呼叫resume函式時才幹得到。
所以,yield函式以下的print語句在下一次的resume呼叫時才被執行。
又所以,當for迴圈第二次執行時,協同程式被掛起,須要等待再一次resume時。for迴圈才幹真正執行完成。
這就是這段**的特殊之處了。
事實上resume函式是有返回值的。
我們試試執行以下的**:
local co = coroutine.create(function()for i = 1, 2, 1 do
coroutine.yield();
endend);
local result, msg = coroutine.resume(co);
print(result);
print(msg);
輸出結果例如以下:
[lua-print] true
[lua-print] nil
resume返回兩個值,第乙個值代表協同程式是否正常執行。第二個返回值自然是代表錯誤資訊。
我們試試讓協同程式出現錯誤:
local co = coroutine.create(function()error("呵呵,報錯了吧");
end);
local result, msg = coroutine.resume(co);
print(result);
print(msg);
輸出結果例如以下:
[lua-print] false
[lua-print] [string "src/main.lua"]:91: 呵呵。報錯了吧
好了,儘管我已經寫了這麼多了,可是我真正想記錄的東西還沒開始寫呢~!
我了個噗,今晚我還能不能好好玩了…
笨木頭Lua專欄 基礎補充04 迭代器初探
今天學習的內容還蠻有意思的,讓我興奮了一下 笨木頭花心貢獻,哈?花心?不,是用心 什麼是迭代器?別傻了,我最討厭的就是名詞解釋了,反正就是用來遍歷集合的一種方式。比如,我們最常用的pairs,如下 local t for k,v in pairs t do print k k v v end 這是一...
笨木頭Lua專欄 基礎補充04 迭代器初探
今天學習的內容還蠻有意思的,讓我興奮了一下 笨木頭花心貢獻,哈?花心?不,是用心 什麼是迭代器?別傻了,我最討厭的就是名詞解釋了,反正就是用來遍歷集合的一種方式。比方,我們最經常使用的pairs,例如以下 local t for k,v in pairs t do print k k v v end...
0基礎lua學習(十三)Metatable
在 lua table 中我們可以訪問對應的key來得到value值,但是卻無法對兩個 table 進行操作。因此 lua 提供了元表 metatable 允許我們改變table的行為,每個行為關聯了對應的元方法。mytable 普通表 mymetatable 元表 setmetatable myt...