Lua协程实现原理

相关 API

API 传入参数 返回值 说明

API传入参数返回值说明
create(f)函数,作为协程运行的主函数返回创建的协程如果还需要运行,需要使用resume操作
resume(co,[val1,…])传入第一个参数是create函数返回的协程,剩下的参数是传递给协程运行的参数。分两种情况,resume成功的情况下返回true以及上一次 yield函数传入的参数;失败情况下返回false,以及错误信息 第一次执行resume操作时,会从create传入的函数开始执行,之后会在该协程主函数调用yield的下一个操作开始执行,直到整个函数执行完毕。第一次执行resume操作时,会从create传入的函数开始执行,之后会在该协程主函数调用yield的下一个操作开始执行,直到整个函数执行完毕。调用resume操作必须在主线程中。
runing返回当前正在执行的协程,如果在主线程中被调用,将返回nil
status返回当前协程的状态,有dead,running,suspend,dead:死亡,runing:正常运行,suspend:挂起
wrap与create类似,传入协程运行的主函数返回创建的协程wrap函数相当于结合了create和resume函数,所不同的是,wrap函数返回的是创建好的协程,下一次直接传入参数调用该协程即可,无需调用resume函数。
yield变长参数,这些是返回,给此次resume函数的返回值。返回下一个resume操作传入的参数值挂起当前协程的运行,调用yield操作,必须在协程中。

测试函数

function foo (a)
    print("foo 函数输出", a)
    return coroutine.yield(2 * a) -- 返回  2*a 的值
end
 
co = coroutine.create(function (a , b)
    print("第一次协同程序执行输出", a, b) -- co-body 1 10
    local r = foo(a + 1)
     
    print("第二次协同程序执行输出", r)
    local r, s = coroutine.yield(a + b, a - b)  -- a,b的值为第一次调用协同程序时传入
     
    print("第三次协同程序执行输出", r, s)
    return b, "结束协同程序"                   -- b的值为第二次调用协同程序时传入
end)
        
print("main", coroutine.resume(co, 1, 10)) -- true, 4
print("--分割线----")
print("main", coroutine.resume(co, "r")) -- true 11 -9
print("---分割线---")
print("main", coroutine.resume(co, "x", "y")) -- true 10 end
print("---分割线---")
print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine
print("---分割线---")

上面测试案例 可以看到Lua中的 协程运行原理, 每次 resume,会从主函数里取 一个yield,并取得 yield的返回值。每次 取玩,yield就失效了,当没得取的时候, 协程就已经是死的了。

其中关键的就是,resume 和yield 之间的 数据交换。

从 from 协程中移动 n 个到 to 协程中。
创建协程在 函数 luaB_cocreate中。

在5.3中协程相关被集成到 lcorolib.c 里。
而在旧版本中 对应的脚本位置是在 lbaselib.c

lcorolib.c 5.3

static int luaB_cocreate (lua_State *L) {
  lua_State *NL;
  luaL_checktype(L, 1, LUA_TFUNCTION);
  NL = lua_newthread(L);
  lua_pushvalue(L, 1);  /* move function to top */
  lua_xmove(L, NL, 1);  /* move function from L to NL */
  return 1;
}

它做的事情:

  • 检查类型,必须是一个函数对象。
  • 创建 lua_State 结构体
  • 移动函数到栈顶,
  • 将该函数从当前的lua_State移动到新创建的协程lua_State(NL)中。

lapi.c ,lua_xmove

LUA_API void lua_xmove (lua_State *from,lua_State *to,int n)
{
    int i; 
    if (from == to) return;
    lua_lock(to);
    api_checknelems(from,n);
    api_check(from,G(from)== G(to))	;
    api_check(from,to->ci->top - to-top >=n);
    from->top -=n;
    for(i =0;i<n;i++)
    {
        setobj2s(to,to->top++,from->top+i);
    }
    
    lua_unlock(to);
}

它主要就是实现了resume和yield函数的参数 两者之间的协程数据交换。

lua协程的执行流程

  • luaB_coresume 等待协程重新开始
  • lua_xmove 移动数据交换
  • lua_resume
  • luaV_execute
  • luaB_yield
  • lua_xmove
  • luaB_coresume
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值