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理解起来还是比较费劲的,
我是花了挺长时间看这段代码的,这里做个备份,方便以后查阅。