skynet之協程池(co_create)

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理解起來還是比較費勁的,
我是花了挺長時間看這段代碼的,這裏做個備份,方便以後查閱。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章