协程的实现依赖于时间片的分隔
协程就是用户态的线程”,Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时刻只能有一个协程在运行,相当于单线程的能力。线程确实比协程的性能更好,因为线程能利用多核达到真正的并行计算,
要理解是什么是“用户态的线程”,必然就要先理解什么是“内核态的线程”。 内核态的线程是由操作系统来进行调度的,在切换线程上下文时,要先保存上一个线程的上下文,然后执行下一个线程,当条件满足时,切换回上一个线程,并恢复上下文。 协程也是如此,只不过,用户态的线程不是由操作系统来调度的,而是由程序员来调度的,是在用户态的。
yield
这个关键字就是用来产生中断, 并保存当前的上下文的, 比如说程序的一段代码是访问远程服务器,那这个时候CPU就是空闲的,就用yield
让出CPU,接着执行下一段的代码,如果下一段代码还是访问除CPU以外的其它资源,还可以调用yield
让出CPU. 继续往下执行,这样就可以用同步的方式写异步的代码了.
优点:
1.无需线程上下文切换的开销
2.无需原子操作锁定及同步的开销
3.方便切换控制流,简化编程模型
4.高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理
缺点:
1.无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
2.进行阻塞操作(如IO读写时)会阻塞掉整个程序
协程的应用多在于异步+回调方式:
function readsome()
io.read();--若不输入则io阻塞
print("yield before");
coroutine.yield();
print("yield after");
end
local co=coroutine.create(readsome);
coroutine.resume(co);
print("contine ");
coroutine.resume(co);
--yield before
--contine?
--yield after
三个状态:suspended(挂起,协同刚创建完成时或者yield之后)、running(运行)、dead(函数走完后的状态,这时候不能再重新resume)。
coroutine.create(arg):根据一个函数创建一个协同程序,参数为一个函数
coroutine.resume(co):使协同从挂起变为运行(1)激活coroutine,也就是让协程函数开始运行,可以传入参数用于初始化;(2)唤醒yield,使挂起的协同接着上次的地方继续运行。该函数可以传入参数
coroutine.status(co):查看协同状态
coroutine.yield():使正在运行的协同挂起,可以传入参数
coroutine.running: 返回当前的协程,如果它被主线程调用的话,返回nil
第一次调用resume时候,因为没有对应的yield在等待它,因此所有传递给resume的额外参数都作为协同程序主函数的参数,resume返回值中,第一个值为true 则表示没有错误,而后面所有的值都是yield传入的参数,对应的yield返回的额外值就是对应resume传入的参数。当一个协同程序结束时,它的主函数所返回的值都将作为对应resume的返回值
-- create coroutine :
assert(not CREATE_CO)
CREATE_CO = function (co_func)
local CurCo = coroutine.running()
if CurCo then
co_func(CurCo)
return
end
local co = coroutine.create(co_func)
coroutine.resume(co, co)
return co
end
CREATE_CO(function(Co)
--阵营数据
for _,Id in pairs(CurHaveZhenYing) do
self:__LoadZhenYing(Co,Id)
end
end)
function __LoadZhenYing(self,Co,ZhenYingId)
local ZhenYingDb = self.ZhenYingDB:Get_Co(Co,ZhenYingId)
if not ZhenYingDb then
self:CreateZhenYingById(ZhenYingId)
else
self:CreateAndAddZhenYing(ZhenYingDb)
end
end
function clsObjDataBase:Get_Co(Co, DataUid)
assert(type(Co) == "thread", self.ServiceId)
local RetData
local NeedYield = true
local Yielded = false
local CBFunc = function(...)
NeedYield = false
RetData = {...}
if Yielded then
coroutine.resume(Co, Co)
end
end
if type(DataUid) == "table" then
self:Get_Multi(DataUid, CBFunc)
else
self:Get(DataUid, CBFunc)
end
if NeedYield then
Yielded = true
coroutine.yield()
end
return unpack(RetData)
end
RetData通过异步函数回调得到