協同程序與線程差很少,也就是一條執行序列,擁有本身獨立的棧、局部變量和指令指針,同時又跟其餘協同程序共享全局變量和其餘大部分東西。從概念上來說,線程與協同程序的主要區別在於:一個具備多線程的程序能夠同時運行幾個線程,而協同程序卻須要彼此協做的運行。就是說,一個具備多個協同程序的程序在任意時刻只能運行一個協同程序,而且正在運行的協同程序只會在其顯示的要求掛起時,它的執行纔會暫停。
多線程
lua將全部關於協同程序的函數放置在一個名爲「coroutine」的table中,函數create用於建立新的血統程序,它只有一個參數,就是一個函數。該函數的代碼就是協同程序須要執行的內容。create會返回一個thread類型的值,用於表示新的協同程序,通常create的參數是一個匿名函數,如:
函數
local co = coroutine.create(function() print("hi) end)
一個協同程序有四種不一樣的狀態:掛起(suspended)、運行(running)、死亡(dead)和正常(normal)。當新建立一個協同程序時,它處於掛起狀態,也就是說,協同程序不會在建立它的時候自動運行。咱們能夠經過函數status來檢查協同程序的狀態。lua
local co = coroutine.create(function() print("hi") end) print(coroutine.status(co)) --suspended
函數coroutine.resume用於啓動或再次啓動一個協同程序的執行,並將其狀態由掛起改成運行。線程
local co = coroutine.create(function() print("hi") end) print(coroutine.status(co)) --suspended coroutine.resume(co) --hi
上面的代碼中調用來resume函數,將協同程序co由suspended改成running狀態,當打印了hi以後,co就處於死亡狀態了。
指針
咱們如今來看一下協程函數的yield,該函數可讓一個運行中的協同程序掛起,而以後能夠再恢復它的運行。看下面的例子:code
local co = coroutine.create(function() for i=1,5 do print(i) coroutine.yield() end end) print(coroutine.status(co)) coroutine.resume(co) print(coroutine.status(co)) coroutine.resume(co) print(coroutine.status(co)) coroutine.resume(co) coroutine.resume(co) coroutine.resume(co) --coroutine.resume(co)注意這句話 print(coroutine.status(co)) coroutine.resume(co)
輸出:orm
suspended 1 suspended 2 suspended 3 4 5 suspended --當把上面的註釋打開,這是輸出爲:dead
在最後一次調用resume時,協同程序的內容已經執行完畢,並已經返回。所以,這時協同程序處於死亡狀態。當在協同程序的執行中發生任何錯誤,Lua是不會顯示錯誤消息的,而是將執行權返回給resume調用。當coroutine.resume的第一個返回值爲false時,就代表協同程序在運行過程當中發生了錯誤;當值爲true時,則代表協同程序運行正常。協程
當一個協同程序A喚醒另外一個協同程序B時,協同程序A就處於一個特殊狀態,既不是掛起狀態(沒法繼續A的執行),也不是運行狀態(是B在運行)。因此將這時的狀態稱爲「正常」狀態。io
Lua的協同程序還具備一項有用的機制,就是能夠經過一對resume-yield來交換數據。在第一次調用resume時,並無對應的yield在等待它,所以全部傳遞給resume的額外參數都視爲協同程序主函數的參數。table
當協同程序中沒有yield時,第一次調用resume,全部傳遞給resume的額外參數都將視爲協同程序主函數的參數,如如下代碼:
local co = coroutine.create(function (a, b, c) print("co", a, b, c) end) coroutine.resume(co, 1, 2, 3) -- co 1 2 3
在resume調用返回的內容中,第一個值爲 true則表示沒有錯誤,然後面全部的值都是對影yield傳入的參數:
local co = coroutine.create(function(a,b) coroutine.yield(a+b,a-b) end) print(coroutine.resume(co,20,10))
輸出:
true 30 10
於此對應的時,yield返回的額外值就是對應resume傳入的參數:
local co = coroutine.create(function() print(coroutine.yield()) end) coroutine.resume(co) coroutine.resume(co,4,5)
輸出:
4 5
最後,當一個協同程序結束時,它的主函數所返回的值都將做爲對應resume的返回值:
local co = coroutine.create(function() return 6,7 end) print(coroutine.resume(co))
輸出:
true 6 7