Skynet_协程

Skynet_协程
BarbecueSkynet_协程
协程的基本概念
每个lua虚拟机中可以有多个协程协调工作,但虚拟机中永远只有一个协程在工作。
情况一:
协程都会绑定一个
主体函数。如果协程还没有运行过,直接调用coroutine_resume(co,...)就会导致协程开始运行,即开始执行主体函数,主体函数收到的参数就是上面的...。调用者此时处于阻塞等待的状态。当主体函数执行完成的时候,coroutine_resume也返回了,对于调用者来说,coroutine_resume返回值就是主体函数的返回值。1
2
3
4
5
6
7
8
9
10local co = coroutine_create(
function(money) --绑定了一个匿名主体函数
-- dosomething
return "绫罗绸缎" --ret的返回值
end
)
local ok,ret = coroutine_resume(co,955) --当协程co执行的时候,当前调用者是阻塞的,即不能立即执行第10行
print(ok,ret)ok是第一个返回值,true表示协程内部执行的时候没有报错情况二:
开始执行了一个主体函数,但在中途,主体函数让出了控制权,即调用coroutine_yield(...)挂起协程,此时coroutine_resume会返回。返回值就是...。1
2
3
4
5
6
7
8
9
10
11
12local co = coroutine_create(
function(money) --绑定了一个匿名主体函数
-- dosomething 1
coroutine_yield("感觉快猝死了")
-- dosomething 2
return "绫罗绸缎"
end
)
local ok,ret = coroutine_resume(co,996) --此时ret的值是 "感觉快猝死了"
print(ok,ret)情况三:
调用者需要协程再次工作,并调用协程。只需调用
coroutine_resume(co,...),就可让协程继续工作。1
2
3
4
5
6
7
8
9
10
11
12
13
14local co = coroutine_create(
function(money) --绑定了一个匿名主体函数
-- dosomething 1
local tip = coroutine_yield("感觉快猝死了") --此时的tip就是 50
print("Much appreciated")
-- dosomething 2
return "绫罗绸缎"
end
)
local ok,ret = coroutine_resume(co,996) --此时ret的值是 "感觉快猝死了"
print(ok,ret) --建议继续工作
ok,ret = coroutine_resume(co,50) --50是打车费
print(ok,ret) --此时ret的值是 "绫罗绸缎"注意:唤醒挂起的协程时,跟第一次执行主体函数一样,也是可以传递参数的。只是协程获取传递进来的参数是在
coroutine_yield函数的左边。coroutine_yield的右边:当前协程让出时传出去的值,coroutine_yield的左边:当前协程被唤醒时,外面传进来的值
skynet的协程框架
skynet的协程池具体工作原理
skynet本身是有协程池,如果需要一个协程,那么首先从协程池中去取;如果协程池中没有,那么就创建一个协程。 co_create(f) 就是获取一个协程。
注意:
f函数不是协程绑定的主体函数。f可以叫做当前协程的任务函数。 刚刚获取一个协程时,任务函数并不会马上执行。只有当协程被唤醒的时候,才会执行这个函数。
1 | local coroutine = coroutine --lua自带的协程库 |
上面的代码看出, co_create 是对lua自带协程库包了一层。而调用 co_create( f ) 时指定的 f 函数 并不是这个协程真正绑定的主体函数。真正的绑定的主体函数是匿名函数 function(...) end 。
针对上面代码分析,举例调用:先假设协程池是空,当需要做一个任务时
先获取一个协程
co = co_reate(f),此时会调用coroutine_create创建一个协程。(此时已经设置好f任务函数)调用
coroutine_resume (co,...),完成任务后协程会放回协程池,同时调用coroutine_yield "SUSPEND"把协程挂起。此时coroutine_resume (co,...)返回了,且返回值中就有"SUSPEND"。注意:协程虽然在逻辑上是回收了,但是它是挂起状态。
外部通过
coroutine_resume(co, new_f)唤醒协程并传入新任务函数new_f,并赋值给f。等待
new_f的参数并执行新任务,外部通过coroutine_resume(co, arg1, arg2, ...)唤醒协程并传入参数。coroutine_yield()返回这些参数,并传递给f。f执行其自身的逻辑。执行完毕后,循环再次开始,清空f,回收协程,挂起等待下一个新任务coroutine_yield "SUSPEND"。
关键点总结
- 协程池:这套机制的核心目的是复用协程,避免重复创建的开销协程执行完一个任务后并不会销毁,而是通过
yield挂起,放回池中,等待下一次被分配新任务。 - 双重 yield:
f(coroutine_yield())体现了其关键作用。它第一次挂起(yield "SUSPEND")是为了接收新任务函数,第二次挂起(yield())是为了接收该任务所需的参数。 - 灵活性:通过这种“函数+参数”分两次传递的方式,协程池可以处理各种不同的任务函数和其对应的参数,非常灵活。



