lua 协程(Coroutine)

总结一下 《lua程序设计第4版》 24章协程的一部分内容:

目录

API

1.coroutine.create

2.coroutine.status

3.couroutine.resume

4.couroutine.yield

通过resume-yield交换数据

总结

5.couroutine.wrap

6.coroutine.running


API

lua协程所有函数都保存在一个coroutine的表中。

1.coroutine.create

        coroutine.create(协程体body) 创建协程,返回一个"thread"类型的协程:

co=coroutine.create(function() print("hi") end) 
print(type(co)) ---> thread

2.coroutine.status

协程有四个状态: 挂起suspended、运行running、正常normal、死亡dead。通过coroutine.status来检测协程的状态:

print(coroutine.status(co))  --->suspended

3.couroutine.resume

当一个协程被创建时,会处于挂起状态,使用 couroutine.resume来启动或唤醒:

  coroutine.resume(co) -- hi

上例执行完后,打印出一个hi,就会终止,变成死亡状态:

 print(coroutine.status(co))  --->dead

4.couroutine.yield

目前为止,协程也就是个复杂的函数调用的方式。而它最强大之处在于yield,该函数可以让一个运行中的协程挂起自己然后在后续恢复运行:

co = coroutine.create(function()
    for i = 1, 10 do 
        print("co",i)
        couroutine.yield()
end)

其中,协程进行了一个循环,循环中输出数字打印后挂起,当唤醒协程后,它就会开始执行直到遇到第一个yield:

coroutine.resume(co)  --> co 1
coroutine.resume(co)  --> co 2
coroutine.resume(co)  --> co 3
...
coroutine.resume(co)  --> co 10
coroutine.resume(co)  --> 不输出任何数据
--当我们再次唤醒它,函数resume将返回false和一条错误信息
print(coroutine.resume(co))
-->false cannot resume dead coroutine

通过resume-yield交换数据

第一个resume函数会把所有额外参数传递给协程的主函数:

co = coroutine.create(function(a,b,c)
    print("co",a,b,c+2)    
end)
coroutine.resume(co,1,2,3) --> co 1 2 5

而resume的返回值中,第一个返回值为true表示没有错误,之后返回值是yield的参数

co = coroutine.create(function(a,b)
    coroutine.yield(a+b,a-b)   
end)
print(coroutine.resume(co,20,10))  --> true 30 10

对应的coroutine.yield的返回值是对应的resume的参数

co = coroutine.create (function (x) 
print (” co1 ”,x) 
print (”co2 ”,coroutine.yield()) 
end)

coroutine.resume(co,"hi") --co1 hi
coroutine.resume(co,4,5) --co2 4 5

可以看到,第一个resume的参数传给了主函数,第二个resume的参数则变成了yield的返回值。

最后,当一个协程运行结束时,主函数的返回值都将变成对应函数resume的返回值:

co = coroutine.create(function()
    return 6,7
end)
print(coroutine.resume(co)) --> true 6 7

总结

1.第一个resume的额外参数会传递给协程的主函数,协程执行结束后会的返回值变成resume的额外返回值

2.第二个resume开始,每一个resume-yield都是对应的,resume的参数是yield的返回值,resume的返回值是yield的参数,一直到最后一个为止,最后一个resume的返回值就是主函数的返回值了

3.综上两点发现,当协程中没有yield时:resume和主函数打交道,resume的额外参数会传递给主函数,resume的返回值也就是主函数执行完后的返回值。但中途有yield函数挂起的话,rsume就会转为和yield打交道:resume的参数是 yield的返回值,resume的返回值是yield的参数

上面分开讲可能比较混乱,下面看一个综合例子:

co = coroutine.create(function(a,b)
   print(coroutine.yield(a+b,a-b))
   return a+1,b+1   
end)
print(coroutine.resume(co,20,10))
print(coroutine.resume(co,15,5))


输出:
true	30	10
15	5
true	21	11

 首先create一个协程,然后调用第一个coroutine.resume(co,20,10)去唤醒协程,因其为第一个resume故20 10传递给主函数参数,之后遇到yield挂起协程所以第一个log是属于外部的print的。如果没有yield那么外部的这个resume的返回值就会是协程函数的返回值,但是有了yield故返回值为yield的参数。之后再次唤醒打印出协程函数里的print,返回值为第二个resume的参数,之后外部的print打印的是协程函数的返回值。

5.couroutine.wrap

function example()
    local co = coroutine.create(function return 2,3 end)
    return function()
        local code,result =coroutine.resume(co)
        return res
    end
end

上面例子将唤醒协程的调用包装在一个函数中,这种使用方法lua提供了一种特殊的函数coroutine.wrap来完成这个功能。和create类似的是它也是创建一个协程,不同点在于函数wrap返回的不是协程本身而是一个函数,当这个函数被调用,协程就会被唤醒。与原先的resume不同,这个函数的返回值中没有错误代码,如上述例子一样,可以用wrap函数简写为:

function example()
    return coroutine.wrap(function() return 2,3 end)
end

6.coroutine.running

coroutine.running() 用来访问当前的协程(这段代码在哪个协程调用就会返回哪个协程的地址,主线程也一样)

local co = coroutine.running()
coroutine.resume(co)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值