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》

相關文章
相關標籤/搜索