協(xié)程具有協(xié)同的性質(zhì),它允許兩個或多個方法以某種可控的方式協(xié)同工作。在任何一個時刻,都只有一個協(xié)程在運行,只有當正在運行的協(xié)程主動掛起時它的執(zhí)行才會被掛起(暫停)。
上面的定義可能看上去比較模糊。接下來讓我講得很清楚一點,假設我們有兩個方法,一個是主程序方法,另一個是一個協(xié)程。當我們使用 resume 函數(shù)調(diào)用一個協(xié)程時,協(xié)程才開始執(zhí)行。當在協(xié)程調(diào)用 yield 函數(shù)時,協(xié)程掛起執(zhí)行。再次調(diào)用 resume 函數(shù)時,協(xié)程再從上次掛起的地方繼續(xù)執(zhí)行。這個過程一直持續(xù)到協(xié)程執(zhí)行結(jié)束為止。
下面的表中列出 Lua 語言為支持協(xié)程而提供的所有函數(shù)以及它們的用法。
| S.N. | 方法和功能 |
|---|---|
| 1 | coroutine.create(f):用函數(shù) f 創(chuàng)建一個協(xié)程,返回 thread 類型對象。 |
| 2 | coroutine.resume(co[,val1,...]): 傳入?yún)?shù)(可選),重新執(zhí)行協(xié)程 co。此函數(shù)返回執(zhí)行狀態(tài),也可以返回其它值。 |
| 3 | coroutine.running():返回正在運行的協(xié)程,如果在主線程中調(diào)用此函數(shù)則返回 nil。 |
| 4 | coroutine.status(co):返回指定協(xié)程的狀態(tài),狀態(tài)值允許為:正在運行(running),正常(normal),掛起(suspended),結(jié)束(dead)。 |
| 5 | coroutine.wrap(f):與前面 coroutine.create 一樣,coroutine.wrap 函數(shù)也創(chuàng)建一個協(xié)程,與前者返回協(xié)程本身不同,后者返回一個函數(shù)。當調(diào)用該函數(shù)時,重新執(zhí)行協(xié)程。 |
| 6 | coroutine.yield(...):掛起正在執(zhí)行的協(xié)程。為此函數(shù)傳入的參數(shù)值作為執(zhí)行協(xié)程函數(shù) resume 的額外返回值(默認會返回協(xié)程執(zhí)行狀態(tài))。 |
讓我們通過下面的例子來理解一下協(xié)程這個概念。
co = coroutine.create(function (value1,value2)
local tempvar3 =10
print("coroutine section 1", value1, value2, tempvar3)
local tempvar1 = coroutine.yield(value1+1,value2+1)
tempvar3 = tempvar3 + value1
print("coroutine section 2",tempvar1 ,tempvar2, tempvar3)
local tempvar1, tempvar2= coroutine.yield(value1+value2, value1-value2)
tempvar3 = tempvar3 + value1
print("coroutine section 3",tempvar1,tempvar2, tempvar3)
return value2, "end"
end)
print("main", coroutine.resume(co, 3, 2))
print("main", coroutine.resume(co, 12,14))
print("main", coroutine.resume(co, 5, 6))
print("main", coroutine.resume(co, 10, 20))
執(zhí)行上面的程序,我們可以得到如下的輸出結(jié)果:
coroutine section 1 3 2 10
main true 4 3
coroutine section 2 12 nil 13
main true 5 1
coroutine section 3 5 6 16
main true 2 end
main false cannot resume dead coroutine
和前面說到的一樣,在例子中我們使用 resume 函數(shù)繼續(xù)執(zhí)行協(xié)程,用 yield 函數(shù)掛起協(xié)程。同樣,從例子中也可以看出如何為執(zhí)行協(xié)程的 resueme 函數(shù)返回多個值。下面我將逐步解釋上面的代碼。
下面這例子中的協(xié)程使用 yield 函數(shù)和 resume 函數(shù)依次返回數(shù)字 1 到 5。示例中,如果沒有協(xié)程對象或?qū)ο笠呀Y(jié)束(dead),則重新創(chuàng)建一個新的協(xié)程對象;若協(xié)程已經(jīng)存在,則執(zhí)行已經(jīng)存在的協(xié)程。
function getNumber()
local function getNumberHelper()
co = coroutine.create(function ()
coroutine.yield(1)
coroutine.yield(2)
coroutine.yield(3)
coroutine.yield(4)
coroutine.yield(5)
end)
return co
end
if(numberHelper) then
status, number = coroutine.resume(numberHelper);
if coroutine.status(numberHelper) == "dead" then
numberHelper = getNumberHelper()
status, number = coroutine.resume(numberHelper);
end
return number
else
numberHelper = getNumberHelper()
status, number = coroutine.resume(numberHelper);
return number
end
end
for index = 1, 10 do
print(index, getNumber())
end
執(zhí)行上述的程序,我們可以得到如下的輸出結(jié)果:
1 1
2 2
3 3
4 4
5 5
6 1
7 2
8 3
9 4
10 5
大家經(jīng)常會把協(xié)程和多線程編程語言中的線程進行對比,但我們要明白,協(xié)程有著與線程類似的特性,但是協(xié)程與線程的區(qū)別在于協(xié)程不能并發(fā),任意時刻只會有一個協(xié)程執(zhí)行,而線程允許并發(fā)的存在。(譯注:譯者認為本質(zhì)上協(xié)程其是就是線程,不過是用戶態(tài)的線罷了,它將調(diào)度問題交由程序開發(fā)人員手動完成。)
我們通過控制程序執(zhí)行順序以滿足獲取某些臨時信息的需求。配合全局變量的使用,協(xié)和會變得更加的靈活方便。