reference:html
http://www.lua.org/manual/5.3/manual.htmlapp
Lua supports coroutines, also called collaborative multithreading. A coroutine in Lua represents an independent thread of execution. Unlike threads in multithread systems, however, a coroutine only suspends its execution by explicitly calling a yield function.ide
You create a coroutine by calling coroutine.create
. Its sole argument is a function that is the main function of the coroutine. The create
function only creates a new coroutine and returns a handle to it (an object of type thread); it does not start the coroutine.函數
You execute a coroutine by calling coroutine.resume
. When you first call coroutine.resume
, passing as its first argument a thread returned bycoroutine.create
, the coroutine starts its execution by calling its main function. Extra arguments passed to coroutine.resume
are passed as arguments to that function. After the coroutine starts running, it runs until it terminates or yields.this
A coroutine can terminate its execution in two ways: normally, when its main function returns (explicitly or implicitly, after the last instruction); and abnormally, if there is an unprotected error. In case of normal termination, coroutine.resume
returns true, plus any values returned by the coroutine main function. In case of errors, coroutine.resume
returns false plus an error object.lua
A coroutine yields by calling coroutine.yield
. When a coroutine yields, the corresponding coroutine.resume
returns immediately, even if the yield happens inside nested function calls (that is, not in the main function, but in a function directly or indirectly called by the main function). In the case of a yield,coroutine.resume
also returns true, plus any values passed to coroutine.yield
. The next time you resume the same coroutine, it continues its execution from the point where it yielded, with the call to coroutine.yield
returning any extra arguments passed to coroutine.resume
.spa
Like coroutine.create
, the coroutine.wrap
function also creates a coroutine, but instead of returning the coroutine itself, it returns a function that, when called, resumes the coroutine. Any arguments passed to this function go as extra arguments to coroutine.resume
. coroutine.wrap
returns all the values returned by coroutine.resume
, except the first one (the boolean error code). Unlike coroutine.resume
, coroutine.wrap
does not catch errors; any error is propagated to the caller.rest
This library comprises the operations to manipulate coroutines, which come inside the table coroutine
. See §2.6 for a general description of coroutines.code
coroutine.create (f)
Creates a new coroutine, with body f
. f
must be a function. Returns this new coroutine, an object with type "thread"
.orm
coroutine.isyieldable ()
Returns true when the running coroutine can yield.
A running coroutine is yieldable if it is not the main thread and it is not inside a non-yieldable C function.
coroutine.resume (co [, val1, ···])
Starts or continues the execution of coroutine co
. The first time you resume a coroutine, it starts running its body. The values val1
, ... are passed as the arguments to the body function. If the coroutine has yielded, resume
restarts it; the values val1
, ... are passed as the results from the yield.
If the coroutine runs without any errors, resume
returns true plus any values passed to yield
(when the coroutine yields) or any values returned by the body function (when the coroutine terminates). If there is any error, resume
returns false plus the error message.
coroutine.running ()
Returns the running coroutine plus a boolean, true when the running coroutine is the main one.
coroutine.status (co)
Returns the status of coroutine co
, as a string: "running"
, if the coroutine is running (that is, it called status
); "suspended"
, if the coroutine is suspended in a call to yield
, or if it has not started running yet; "normal"
if the coroutine is active but not running (that is, it has resumed another coroutine); and "dead"
if the coroutine has finished its body function, or if it has stopped with an error.
coroutine.wrap (f)
Creates a new coroutine, with body f
. f
must be a function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume
. Returns the same values returned by resume
, except the first boolean. In case of error, propagates the error.
coroutine.yield (···)
Suspends the execution of the calling coroutine. Any arguments to yield
are passed as extra results to resume
.
Lua的coroutine 跟thread 的概念比較類似,可是也不徹底相同。一個multi-thread的程序,能夠同時有多個thread 在運行,可是一個multi-coroutines的程序,同一時間只能有一個coroutine 在運行,並且當前正在運行的coroutine 只有在被顯式地要求掛起時,纔會掛起。Lua的coroutine 是一個強大的概念,儘管它的幾個主要應用都比較複雜。
Lua將coroutine相關的全部函數封裝在表coroutine 中。create 函數,建立一個coroutine ,以該coroutine 將要運行的函數做爲參數,返回類型爲thread
co=coroutine.create(function() print("hello") end) print(co,type(co))
運行結果:
thread: 0xfd2540 thread
coroutine 有4個不一樣的狀態:suspended, running, dead, normal。當新create 一個coroutine的時候,它的狀態爲suspended ,意味着在create 完成後,該coroutine 並無當即運行。咱們能夠用函數status 來查看該coroutine 的狀態:
co=coroutine.create(function() print("hello") end) print(co,type(co)) print("status:"..coroutine.status(co))
運行結果:
thread: 0xfd2540 thread status:suspended
函數coroutine.resume (恢復)運行該coroutine,將其狀態從suspended變爲running:
co=coroutine.create(function() print("hello") end) print(co,type(co)) print("status:"..coroutine.status(co)) coroutine.resume(co)
運行結果:
thread: 0xfd2540 thread status:suspended hello
在該示例中,coroutine運行,輸出一個「hello」就結束了,該coroutine變爲dead狀態:
co=coroutine.create(function() print("hello") end) print(co,type(co)) print("status:"..coroutine.status(co)) coroutine.resume(co) print("status:"..coroutine.status(co))
運行結果:
thread: 0xb16690 thread status:suspended hello status:dead
coroutine的真正強大之處在於它的yield 函數,它能夠將正在運行的coroutine 掛起,並能夠在適當的時候再從新被喚醒,而後繼續運行。下面,咱們先看一個簡單的示例:
co1=coroutine.create(function() for i=1, 10 do print("co1 ", i) coroutine.yield() end print("end") end) function test() for i=1, 12 do co2 = coroutine.resume(co1) print(co2,"status:"..coroutine.status(co1)) end end test()
運行結果:
co1 1 true status:suspended co1 2 true status:suspended co1 3 true status:suspended co1 4 true status:suspended co1 5 true status:suspended co1 6 true status:suspended co1 7 true status:suspended co1 8 true status:suspended co1 9 true status:suspended co1 10 true status:suspended end true status:dead false status:dead
該coroutine每打印一行,都會被掛起,看起來是否是在運行yield 函數的時候被掛起了呢?當咱們用resume 喚醒該coroutine時,該coroutine繼續運行,打印出下一行,而且返回值爲true。直到最後沒有東西打印出來的時候,該coroutine退出循環,變爲dead狀態(注意最後那裏的狀態變化)。若是對一個dead狀態的coroutine進行resume 操做,coroutine.resume的返回值爲false。
注意,resume 是運行在protected mode下。當coroutine內部發生錯誤時,Lua會將錯誤信息返回給resume 調用。
當一個coroutine A在resume另外一個coroutine B時,A的狀態沒有變爲suspended,咱們不能去resume它;可是它也不是running狀態,由於當前正在running的是B。這時A的狀態其實就是normal 狀態了。
Lua的一個頗有用的功能,resume-yield對,能夠用來交換數據。下面是4個小示例:
1)main函數中沒有yield,調用resume時,多餘的參數,都被傳遞給main函數做爲參數,下面的示例,1 2 3分別就是a b c的值了:
co3=coroutine.create(function(a,b,c) print("hello",a,b,c) end) print(coroutine.resume(co3,1,2,3)) print("status:"..coroutine.status(co3)
運行結果:
hello 1 2 3 true status:dead
2)main函數中有yield,全部被傳遞給yield的參數,都被返回。所以resume的返回值,除了標誌正確運行的true外,還有傳遞給yield的參數值:
co4=coroutine.create(function(a,b) print("hello",a,b) coroutine.yield(a+b, a-b) end) print(coroutine.resume(co4,10,5)) print("status:"..coroutine.status(co4))
運行結果:
hello 10 5 true 15 5 status:suspended
3)yield也會把多餘的參數返回給對應的resume,以下:
co6=coroutine.create(function(a,b) print("hello",a,b,coroutine.yield()) end) print(coroutine.resume(co6)) print(coroutine.resume(co6,10,5)) print("status:"..coroutine.status(co6))
運行結果:
true hello nil nil 10 5 true status:dead
其中print(coroutine.resume(co6))返回值爲true,這是由於 yield沒有返回,print就根本還沒運行。
另外:
co5=coroutine.create(function(a,b) print("hello",a,b) coroutine.yield() end) print(coroutine.resume(co5)) print(coroutine.resume(co5,10,5)) print("status:"..coroutine.status(co5))
運行結果:
hello nil nil true true status:dead
仔細比較上面兩個例子的區別,coroutine.yield()一個是位於print()函數的參數,另一個和print()獨立,致使運行結果不一樣。
4)當一個coroutine結束的時候,main函數的全部返回值都被返回給resume:
co7=coroutine.create(function() return "finish","ok" end) print(coroutine.resume(co7)) print("status:"..coroutine.status(co7)
運行結果:
true finish ok status:dead