AKever

导航

lua 协同程序 coroutine

Lua 协同程序 coroutine

co = coroutine.create(function() 
        print("hi") 
        coroutine.yield() --挂起(suspended)
    end)
coroutine.status(co)
coroutine.resume(co)

Lua将所有关于协同程序的函数放置在一个名为 coroutine 的table中。函数create用于创建新的协同程序, 他只是一个参数,就是一个函数。该函数的代码就是协同程序所需要执行的内容。create会返回一个thread类型的值,用以表示新的协同程序。通常create的参数是一个匿名函数,例如:

co = coroutine.create(function() print("hi") end)
print(co) -->thread:0x8071d98

一个协同程序可以出于不同的4中状态:挂起(suspended), 运行(running), 死亡(dead)和正常(normal)

当创建一个协同程序,它是出于挂起的状态。也就是说,协同程序不会再创建的时候后自动执行内容。可以同函数status来检查协同程序的状态:

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

函数coroutine.resume用于启动或再次启动一个协同程序的执行, 并将其状态改为运行:

coroutine.resume(co) -->hi

在本例中,协同程序的内容只是简单的打印hi,后便终止啦,让后他就处于死亡状态,也就再也无法返回了:

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

==========================================================

 

协同程序的强大在于函数yield的使用上,该函数可以让一个运行中的协同程序挂起,之后可以再回复他的运行。以下是简单示例:

co = coroutine.create(function ()
       for i=, 10 do
               print("co", i)
               coroutine.yield()  --挂起(suspended)
       end
end)

当唤醒这个协同程序时,他就会开始执行,直到第一个yield:

coroutine.resume(co) -->co 1

如果此时检查其状态,会发现协同程序处于挂起状态,因此可以再次恢复其运行:

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

...more

lua2 74页

 

===========================================================

转载:http://timyang.blog.51cto.com/1539170/307675

原理探析

  • coroutine创建的所谓的“线程”都不是真正的操作系统的线程,实际上是通过保存stack状态来模拟的。
  • 由于是假的线程,所以切换线程的开销极小,同时创建线程也是轻量级的,new_thread只是在内存新建了一个stack用于存放新coroutine的变量,也称作lua_State

LUA_API lua_State *lua_newthread (lua_State *L)

  • 调用yield()当前线程交出控制权,同时还可以通过stack返回参数。调用resume的线程(可理解为主线程)获得返回的参数。
  • Lua yield()和Java中的Thread.yield()有点相似,但是区别更大。Java中的yield调用后只是将当前CPU切换到另外一个线程,CPU可能随时会继续回到线程执行。
  • 我更倾向于把Lua中的yield()和resume()和Java中的wait()和notify()来对比。它们表现的行为基本一致。
  • 关于stack实现也可参看Yufeng(Erlang高手)的分析文章 lua coroutine是如何实现的?

===========================================================

协同程序 resume-yield

--协同程序的创建

co1 = coroutine.create(function() print("hi") end)
print(co1)      --thread: 0x8039288
print(coroutine.status(co1))  --suspended
coroutine.resume(co1)        --hi
print(coroutine.status(co1))  --dead

--yield的使用

co2 = coroutine.create(function()
    for i=1, 10 do
        print("co2", i)
        coroutine.yield() --wait
    end
end)

coroutine.resume(co2)  --1
coroutine.resume(co2)  --2
coroutine.resume(co2)  --3
coroutine.resume(co2)  --4
coroutine.resume(co2)  --5
coroutine.resume(co2)  --6
coroutine.resume(co2)  --7
coroutine.resume(co2)  --8
coroutine.resume(co2)  --9
coroutine.resume(co2)  --10

--第一次调用resume时,并没有对应的yield在等待他,因此所有传递给resume的额外参数都将视为协同程序的函数的参数

co3 = coroutine.create(function(a, b, c)
        print("co3", a, b, c)
    end)
coroutine.resume(co3, 1, 2, 3) --resume 传入参数

--在resume调用返回的内容中,第一个值为true表示没有错误,而后面所有的值都是对应yield传入的参数

co4 = coroutine.create(function(a, b)
        coroutine.yield(a+b, a-b)   --yield返回参数,传入resume
    end)

print(coroutine.resume(co4, 20, 10))   --resume 传入参数  -->true 30 10

--以此对应,yield返回的额外值就是对应resume传入的参数

co5 = coroutine.create(function()
        print("co5", coroutine.yield())    -- co5  4  5
    end)
coroutine.resume(co5)
coroutine.resume(co5, 4, 5)

--最后当一个协同程序结束时,它的主函数所返回的值都将作为对应的resume的返回值

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

 

 

-----end!!!

posted on 2014-08-04 10:44  AKever  阅读(1523)  评论(0)    收藏  举报