local coroutine_pool = {}
local coroutine_yield = coroutine.yield
local function co_create(f)
local co = table.remove(coroutine_pool)
if co == nil then
co = coroutine.create(function(...)
f(...)
while true do
f = nil
coroutine_pool[#coroutine_pool+1] = co
f = coroutine_yield "EXIT"
f(coroutine_yield())
end
end)
else
coroutine.resume(co, f)
end
return co
end
這段代碼是創建協程的,並把創建出來的協程自動加到一個pool裏。
-- test code
print(#coroutine_pool)
local co1 = co_create(function() print("111111") end)
print(coroutine.status(co1))
print(coroutine.resume(co1))
print(#coroutine_pool)
local co2 = co_create(function() print("222222") end)
print(coroutine.resume(co2))
print(co1, co2)
print(#coroutine_pool)
result:
0
suspended
111111
true EXIT
1
222222
true EXIT
thread: 0086F890 thread: 0086F890
1
測試代碼中,第一行先打印出coroutine_pool的數量,當然是0。
下面一行,使用co_create
創建一個協程,狀態爲suspended
, 然後調用resume啓動,這時打出1111111,然後執行到while true裏後,先把賦值爲nil(這句沒有應該也一樣),再把co放到pool裏,然後調用yield使協程掛起,並返回EXIT給調用resume的地方。
再下一行,打印出pool的數量爲1.
local co2 = co_create(function() print("222222") end)
這一行創建了第二個協程,進入co_create函數後,第一行首先從pool裏彈出一個co, 由於此時pool裏有1個協程了,所以if條件走到了else那裏,在這裏面直接調用resume恢復協程的運行,並把執行函數f作爲參數傳遞進去,這個resume會回到之前掛起的地方執行,也就是
f = coroutine_yield "EXIT"
這一行,yield返回的值是resume傳進來的,也就是co2的執行函數,這裏就是我寫的print(‘222222’)那個函數。
再看下一行:
f(coroutine_yield())
這裏馬上又調用了一個yield是爲什麼呢?這是爲了模擬真實coroutine.create的行爲,協程創建後是掛起的,必須由外部調用resume纔會運行。所以我們創建的co2這時就掛起在這一行了,f(…)還沒運行。
之所以要把yield的參數傳給f, 是爲了模擬coroutine.resume的行爲,在resume時,除了第一個參數co, 後面的參數都會傳給協程的執行函數,這裏這樣寫可以達到同樣的效果,非常聰明的寫法。
回到測試代碼:
print(coroutine.resume(co2))
這裏再次恢復協程的運行,打印出
222222
true EXIT
while true do
f = nil
coroutine_pool[#coroutine_pool+1] = co
f = coroutine_yield "EXIT" --再次停在這裏,如此反覆
f(coroutine_yield())
end
下面一行
print(co1, co2)
打出來的結果是
thread: 006DF890 thread: 006DF890
我們已經知道co1和co2是同一個thread了,這裏驗證一下。
最後再打出pool的數量,仍然是1.
以上就是對skynet中co_create這個函數的分析了,lua中的coroutine理解起來還是比較費勁的,
我是花了挺長時間看這段代碼的,這裏做個備份,方便以後查閱。