笨木頭Lua專欄 基礎補充07 協同程式初探

2021-09-07 13:06:17 字數 4223 閱讀 6159

哎。周五晚上我都還這麼努力看書。真是好孩子。(小若:不想吐槽了)

事實上我都準備玩遊戲

看電影去的了。可是這書就擺在桌子

上。並且正對著我,就想著。掃兩眼吧。

結果一掃就不正確勁了,由於這內容有點繞,有點小混亂,假設我如今不記錄下來的話。下周一可能又要又一次看一次了。

好吧,今天我們來聊聊協同程式。

笨木頭花心貢獻,哈?花心?不,是用心~

大家都知道執行緒吧?都知道多執行緒吧?協同程式就和這執行緒差點兒相同,可是又有比較明顯的區別。

多個協同程式在隨意時刻僅僅能執行乙個,儘管執行緒在某種意義上也是這樣,但這不是一樣的概念。

換句話說,乙個協同程式在執行的時候。其它協同程式是無法獲得執行的機會的。

僅僅有正在執行的協同程式主動掛起時,其它協同程式才有機會執行。

而執行緒呢?即使不主動休眠。也非常有可能由於輪片時間到達而把執行機會讓給其它執行緒。

建立協同程式非常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...