協同程序與線程thread差不多,也就是一條執行序列,擁有自己獨立的棧、局部變量和命令指針,同時又與其他協同程序共享全局變量和其他大部分東西。從概念上講線程與協同程序的主要區別在於,一個具有多個線程的程序可以同時運行幾個線程,而協同程序卻需要彼此協作的運行。也就是說多個協同程序在任意時刻只能運行一個協同程序,只有當正在運行的協同程序顯式的要求掛起時,它的執行才會暫停。
一、協同程序coroutine
Lua將所有關於協同程序的函數放置在一個名為“coroutine”的table中。
1、coroutine.create創建一個thread類型的值表示新的協同程序,返回一個協同程序。
2、coroutine.status檢查協同程序的狀態(掛起suspended、運行running、死亡dead、正常normal)。
3、coroutine.resume啟動或再次啟動一個協同程序,並將其狀態由掛起改為運行。
4、coroutine.yield讓一個協同程序掛起。
5、coroutine.wrap同樣創建一個新的協同程序,返回一個函數。
創建協同程序:create函數,接受一個函數值作為協同程序的執行內容,並返回一個協同程序。


啟動或再次啟動一個協同程序:resume函數,接受一個協同程序及一個或多個參數用於值傳遞給協同程序。


掛起協同程序:yield函數,讓一個協同程序掛起,並等待下次恢復它的運行。它可以接受resume函數傳遞進來的所有參數。


關於wrap函數的使用,wrap函數比create函數更易使用。它提供了一個對於協同程序編程實際所需的功能,即一個可以喚醒協同程序的函數。但也缺乏靈活性。無法檢查wrap所創建的協同程序的狀態,此外,也無法檢測出運行時的錯誤。


各種協同狀態的演示:


首先,Lua提供的是一種:”非對稱的協同程序“。也就是說,Lua提供了兩個函數來控制協同程序的執行,一個用於掛起執行,另一個用於恢復執行。而一些其他的語言則提供了”對稱的協同程序“,其中只有一個函數用於轉讓協同程序之間的執行權。
二、管道與過濾器filter
關於協同程序的示例就是”生產者--消費者“的問題。其中涉及到兩個函數,一個函數不斷的產生值,另一個函數不斷的消費這些值。當消費者需要一個新的值時,它喚醒生產者。生產者返回一個新值后停止運行,等待消費者的再次喚醒。這種設計稱為”消費者驅動“。通過resume—yield 函數之間的值交換可以輕易的實現程序。
過濾器filter,是一種位於生產者與消費者之間的處理功能,可以進行數據轉換。它既是消費者又是生產者,它喚醒生產者促使其生產新值,然后又將變換后的值傳遞給消費者。
1 --管道與過濾器filter 2 --生產者與消費者通過過濾器進行值傳遞 3 --這種模式通過消費者驅動生產者進行產生。 4 5 --計數器函數 6 function getCount( x ) 7 return function() 8 x=x+1 9 return x 10 end 11 end 12 --創建閉合計數器 13 local count = getCount(0) 14 --發送新值 15 function send(x) 16 coroutine.yield(x) 17 end 18 --啟動一個協同程序 19 function receive( pro ) 20 local status,value = coroutine.resume( pro ) 21 return value 22 end 23 --生產者 24 function producter() 25 while true do 26 send( count() ) 27 end 28 end 29 --過濾器,接受一個生產者 30 function filter( pro ) 31 local x = 0 32 return function() 33 while true do 34 x = receive( pro ) 35 send(x) 36 end 37 end 38 end 39 --消費者,接受一個生產者協同程序及控制條件,控制條件防止死循環 40 --假設有100個消費者,驅動生產者來生產 41 function consumer( pro,num ) 42 local x = 0 43 while x < num do 44 x = receive( pro ) 45 print( x ) 46 end 47 end 48 49 local pro = coroutine.create( producter ) 50 local fil = coroutine.create( filter( pro ) ) 51 consumer( fil,100 ) 52 53 print( "消費者協同程序狀態:",coroutine.status(pro) ) 54 print( "生產者協同程序狀態:",coroutine.status(fil) )
三、協同程序實現的迭代器
通過“生產者—消費者”模型可以很輕松的創建迭代器,同樣是通過協同程序來進行控制。
--以協同程序實現Lua迭代器 local tab = { 1,2,3,4,5,6 } function corFun( tab,num ) num = num or 0 return function() while true do num = num +1 if( num > #tab ) then return end coroutine.yield(tab[num]) end end end function cor( tab ) local cor = coroutine.create( corFun( tab ) ) return function ()--迭代器 local status,value = coroutine.resume( cor ) return value end end for v in cor( tab ) do if v then print(v) else break end end
