lua编程之协程介绍

一,lua协程简介 html

协程(coroutine),意思就是协做的例程,最先由Melvin Conway在1963年提出并实现。跟主流程序语言中的线程不同,线程属于侵入式组件,线程实现的系统称之为抢占式多任务系统,而协程实现的多任务系统成为协做式多任务系统。线程因为缺少yield语义,因此运行过程当中不可避免须要调度,休眠挂起,上下文切换等系统开销,还须要当心使用同步机制保证多线程正常运行。而协程的运行指令系列是固定的,不须要同步机制,协程之间切换也只涉及到控制权的交换,相比较线程来讲是很是轻便的。不过同一时刻能够有多个线程运行,但却只能有一个协程运行。 git

协程具备两个很是重要的特性: github

1. 私有数据在协程的间断式运行期间一直有效 shell

2. 协程每次yield后让出控制权,下次被resume后从中止点开始继续执行 编程

通俗的说,比较像一个带有静态数据并且具备多个进入点和返回点的函数,下面经过一个简单例子看看这个性质:数据结构

co = coroutine.create(
function(a)
  print("a = "..a)
  c = coroutine.yield(a+1)
  print("c = "..c)
  return c*2
end
)
_, b = coroutine.resume(co, 1)
print("b = "..b)
_, d = coroutine.resume(co, b )
print("d = "..d)

运行结果:多线程

a = 1 函数

b = 2 lua

c = 2 spa

d = 4

协程co中除了通常函数具备的进入点(函数入口处)和返回点(函数结尾),在yield出还有一个进入点和返回点。主程序第一次resume时将1传给参数a,运行到yield时,协程返回控制权给主程序,并经过yield的参数提供返回值,因而b=a+1,再次resume时,主程序经过参数b将数据传给co的变量c,从而从第二个入口点进入函数,最后返回值c*2传给d。

resume/yield语义实现的协程属于非对称协程,在非对称协程中,调用者和被调用者的关系是固定的,调用者经过resume将控制流转到被调用者,被调用者经过yield只能返回到调用者,而不能返回到其余协程。好比A resume B resume C, C yield只能到B,而不能到A或其余协程。

世间万物都是对立又统一的,既然存在非对称协程,固然就存在对称协程。对称协程只有一个语义能够将控制流直接转到目的协程。

非对称协程和对称协程的表达能力是同样的,lua中只实现了非对称协程,一个重要缘由是lua是c实现的,非对称协程的调用与被调用关系与c的函数调用很是相似,方便lua和c的扩展编程。

二,协程实战

下面例子利用协程实现经典的生产者-消费者模型。

count = 10
productor = coroutine.create( 
  function () 
    i = 0 
    while(true) do 
      i = i+1 
      coroutine.yield(i) 
    end 
  end 
) 

consumer = coroutine.create( 
function(co) 
  n = 1 
  while(n<count) do 
  _, v = coroutine.resume(co) 
    print(v) 
    n = n+1 
  end 
end 
) 

coroutine.resume(consumer, productor)

consumer启动productor,productor产生一个item后经过yield传回给consumer,而后挂起等待consumer下次resume,很是简单直观。

协程的另外一个重要做用是做为迭代器,依次访问数据结构的元素。下面代码展现了先序访问二叉树的方法。

l = { 
  v = 1, 
  left = nil, 
  right = nil, 
} 

r = { 
  v = 2, 
  left = nil, 
  right = nil, 
} 

root = { 
  v = 3, 
  left = l, 
  right = r, 
} 

preorder = function(root) 
  if(root == nil) then return end 
  coroutine.yield(root.v) 
  preorder(root.left) 
  preorder(root.right) 
end 

preco = coroutine.create(preorder) 


view = function(co, root) 
  state, v = coroutine.resume(co, root) 
  if(state == false) then return end 
  print(v) 
  while(true)  do 
    state, v = coroutine.resume(co) 
    if(state == false or v == nil) then return end 
    print(v) 
  end 
end 
view(preco, root)

对于coroutine, 这里介绍了一个很是轻量级协程的实现原理,云风经过uconext实现了相似于lua的协程库,有兴趣的同窗能够研究研究。

 

reference:

《coroutines in C》

相关文章
相关标签/搜索