加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Lua协程

发布时间:2020-12-14 21:56:17 所属栏目:大数据 来源:网络整理
导读:协程是非抢断式的多线程方式,看上去像多线程,其实如同名字说的—协程,在协调多段程序的运行并且各自的代码段是有自己独立的变量的cache。本文主要通过实例将协程的处理讲清楚。 resume和yield是一个很好的桥梁,将代码段之间方便的传输参数。 接口函数:

协程是非抢断式的多线程方式,看上去像多线程,其实如同名字说的—协程,在协调多段程序的运行并且各自的代码段是有自己独立的变量的cache。本文主要通过实例将协程的处理讲清楚。
resume和yield是一个很好的桥梁,将代码段之间方便的传输参数。

接口函数:

函数 参数 说明
coroutine.create f 创建协程
coroutine.resume co [,val1,···] 开启或者继续一个协程
coroutine.running 返回是否协程在运行,或者返回nil当被主线程调用时
coroutine.status co 返回协程状态:running,suspended,normal,dead
coroutine.wrap co 原生态创建协程
coroutine.yield 挂起正在执行的

coroutine.wrap有点特别,这个是我摘抄文档中的解释:
类似 coroutine.create , coroutine.wrap 这个函数也将创建一个 coroutine , 但是它并不返回 coroutine 本身,而是返回一个函数取而代之。一旦你调用这个返回函数,就会切入 coroutine 运行。 所有传入这个函数的参数等同于传入 coroutine.resume 的参数。 coroutine.wrap 会返回所有应该由除第一个(错误代码的那个布尔量) 之外的由 coroutine.resume 返回的值。 和 coroutine.resume 不同, coroutine.wrap 不捕获任何错误; 所有的错误都应该由调用者自己传递。

官方的一个实例:

function foo (a)
   print("foo",a)
   return coroutine.yield(2*a)
 end

 co = coroutine.create(function (a,b)
       print("co-body",a,b)
       local r = foo(a+1)
       print("co-body",r)
       local r,s = coroutine.yield(a+b,a-b)
       print("co-body",r,s)
       return b,"end"
 end)

 print("main",coroutine.resume(co,1,10))
 print("main","r"))
 print("main","x","y"))
 print("main","y"))

输出结果:

>lua -e "io.stdout:setvbuf 'no'" "test.lua" 
co-body 1   10
foo 2
main    true    4
co-body r
main    true    11  -9
co-body x   y
main    true    10  end
main    false   cannot resume dead coroutine

调用顺序:

Created with Rapha?l 2.1.0 主线程 主线程 协程 协程 resume(co,1,10) 主线程挂起,唤起协程 foo (1+1) coroutine.yield(2*2) 协程挂起,主线程唤醒 return resume()->主线程获得2*2返回值 coroutine.resume(co,"r")主线程挂起,唤起协程 local r = foo(a+1)触发resume("r")参数赋值给local r coroutine.yield(a+b,a-b)协程挂起,主线程唤醒,将会1+10,1-10 print("main",coroutine.resume(co,"r"))将yield的参数输出 local r,s = coroutine.yield(a+b,a-b)主线程中输入的"x","y"变量将会被赋值给r,s 由于协程已经执行全部的流程最终将会把流程交回给主线程,协程将会变成dead态 X,协程已经不再工作状态,所以造成程序直接返回,服务器不能唤起

看完这个例子之后,其实可以看出来这两个线程其实一直在配合做事情。当resume被调用的时候,主线程就暂停了活动,将运行的权限交给了coroutine来做事。当coroutine yield的时候,将会直接触发自己的coroutine暂停,激活主线程的resume的return,接着做事。所以理论上对一个coroutine的调用,函数中有几个yield,主线程的代码中需要些多少个resume函数,否则如果主线程只对coroutine做一次resume。但是这个也不会造成太多的内存问题,协程对象被释放掉之后也将不会存在内存泄露
下面就举个例子来做一下测试说明此问题。

function first_phase(a)
    -- coroutine first phase
    return coroutine.yield( a + 1 )
end


collectgarbage('collect')
print(string.format("after full garbage-collection cycle,memory: %d k",collectgarbage('count')))

for i = 1,100 do
    local co = coroutine.create( function ( a,b )
        local l_a,l_b = a,b
        local m1 = first_phase(a)
        -- coroutine second phase
        local m2 = coroutine.yield( m1 + 1 )
        -- coroutine third phase
        return input * b
    end)

    first_return = coroutine.resume( co,10,8 )
    -- without to call resume let coroutine to finish

    if i == 99 then
        collectgarbage('collect')
        print(string.format("after full garbage-collection cycle,collectgarbage('count')))
    end
end

collectgarbage('collect')
print(string.format("after full garbage-collection cycle,collectgarbage('count')))

输出:

after full garbage-collection cycle,memory: 20 k
after full garbage-collection cycle,memory: 21 k
after full garbage-collection cycle,memory: 20 k

这个说明了问题,就是其实在coroutine的Up-value的数据都是被保存在coroutine对象中。一旦释放掉这些对象,其Up-value数据也将会被回收,即使是这个coroutine状态还是在suspended之下也没有关系。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读