第一版是為 Lua 5.0 編寫的。儘管對於後續版本而言仍然相當相關,但有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買這本書,您也可以協助 支援 Lua 專案。
![]() |
Lua 中的 程式設計 | ![]() |
第一部分。語言 第 9 章。協程 |
Lua 將所有協程函式封裝在 coroutine
表格中。create
函式用來建立新的協程。它有一個單一引數,一個包含協程將執行的程式碼的函式。它會傳回一個類型為 thread
的值,代表新的協程。通常,create
的引數是一個匿名函式,如下所示
co = coroutine.create(function () print("hi") end) print(co) --> thread: 0x8071d98
協程可以處於三種不同狀態之一:暫停、執行和結束。當我們建立一個協程時,它會從暫停狀態開始。這表示協程在我們建立它時不會自動執行其主體。我們可以使用 status
函式來檢查協程的狀態
print(coroutine.status(co)) --> suspended函式
coroutine.resume
會(重新)開始執行一個協程,將其狀態從暫停變更為執行
coroutine.resume(co) --> hi在此範例中,協程主體只會印出
"hi"
並終止,讓協程處於結束狀態,無法再傳回
print(coroutine.status(co)) --> dead
到目前為止,協程看起來只不過是一種複雜的函式呼叫方式。協程的真正力量來自 yield
函式,它允許正在執行的協程暫停其執行,以便稍後可以繼續執行。讓我們看一個簡單的範例
co = coroutine.create(function () for i=1,10 do print("co", i) coroutine.yield() end end)現在,當我們繼續執行此協程時,它會開始執行並執行到第一個
yield
coroutine.resume(co) --> co 1如果我們檢查其狀態,我們可以看到協程已暫停,因此可以再次繼續執行
print(coroutine.status(co)) --> suspended從協程的角度來看,當協程暫停時發生的所有活動都發生在它呼叫
yield
的過程中。當我們恢復協程時,這個呼叫yield
的動作最後會回傳,而協程會繼續執行,直到下一個 yield 或結束
coroutine.resume(co) --> co 2 coroutine.resume(co) --> co 3 ... coroutine.resume(co) --> co 10 coroutine.resume(co) -- prints nothing在最後一次呼叫
resume
時,協程主體完成迴圈後回傳,因此協程現在已經結束了。如果我們再次嘗試恢復它,resume
會回傳false以及錯誤訊息
print(coroutine.resume(co)) --> false cannot resume dead coroutine請注意,
resume
會在受保護模式下執行。因此,如果協程內部有任何錯誤,Lua不會顯示錯誤訊息,而是會將錯誤訊息回傳給resume
呼叫。
Lua中一個有用的功能是,resume-yield配對可以在它們之間交換資料。第一個resume
,沒有對應的yield
在等待它,會將它的額外參數作為協程主函式的參數傳遞
co = coroutine.create(function (a,b,c) print("co", a,b,c) end) coroutine.resume(co, 1, 2, 3) --> co 1 2 3呼叫
resume
會在true(表示沒有錯誤)之後回傳傳遞給對應yield
的任何參數
co = coroutine.create(function (a,b) coroutine.yield(a + b, a - b) end) print(coroutine.resume(co, 20, 10)) --> true 30 10對稱地,
yield
會回傳傳遞給對應resume
的任何額外參數
co = coroutine.create (function () print("co", coroutine.yield()) end) coroutine.resume(co) coroutine.resume(co, 4, 5) --> co 4 5最後,當協程結束時,它的主函式回傳的任何值都會傳遞給對應的
resume
co = coroutine.create(function () return 6, 7 end) print(coroutine.resume(co)) --> true 6 7
我們很少在同一個協程中使用所有這些功能,但它們都有各自的用途。
對於那些已經對協程有所了解的人來說,在我們繼續之前,釐清一些概念非常重要。Lua提供了我稱之為非對稱協程的功能。這表示它有一個函式可以暫停協程的執行,以及另一個函式可以恢復暫停的協程。其他一些語言提供對稱協程,其中只有一個函式可以將控制權從一個協程傳遞到另一個協程。
有些人稱非對稱協程為半協程(因為它們不對稱,所以它們並非真正的協同)。然而,其他人使用相同的術語半協程來表示協程的受限實作,其中協程只能在它不在任何輔助函式內部時暫停執行,也就是說,當它在控制堆疊中沒有待處理的呼叫時。換句話說,只有這種半協程的主體才能 yield。Python 中的產生器就是這種意義上的半協程的一個例子。
與對稱和非對稱協程之間的差異不同,協程和產生器(如 Python 中所呈現)之間的差異很深;產生器根本不夠強大,無法實作我們可以用真正的協程編寫的幾個有趣的結構。Lua 提供真正的非對稱協程。那些偏好對稱協程的人可以在 Lua 的非對稱設施之上實作它們。這是一項簡單的任務。(基本上,每個傳輸都會執行一個 yield,然後執行一個 resume。)
版權所有 © 2003–2004 Roberto Ierusalimschy。保留所有權利。 | ![]() |