概括:1.創建協程2.coroutine的函數3.coroutine的基本流程4.yield對coroutine流程的干預5.resume, function()以及yield之間的參數傳遞和返回值傳遞
原文地址:http://blog.csdn.net/dingkun520wy/article/details/50212199
1.創建協程
協程和多線程下的線程類似:有自己的堆棧,自己的局部變量,有自己的指令指針,但是和其他協程程序共享全局變量等信息。線程和協程的主要不同在於:多處理器的情況下,概念上來說多線程是同時運行多個線程,而協程是通過協作來完成,任何時刻只有一個協程程序在運行。並且這個在運行的協程只有明確被要求掛起時纔會被掛起。
--創建協程
co = coroutine.create(function ()
print("hi")
end)
--啓動協程
coroutine.resume(co)
2.coroutine的函數
(1) coroutine.create() 創建協程
(2) coroutine.resume() 運行協程,可以向協程內傳遞參數
(3) coroutine.yield() 掛起協程,可以向外傳遞參數
(4) coroutine.status() 返回協程當前狀態,coroutine的狀態分爲suspend, running, dead三種。
3.coroutine的基本流程
co = coroutine.create(function(a, b)
print(coroutine.status(co), "start") --執行代碼,coroutine狀態爲running--->(3)
print("co", a, b)
print(coroutine.status(co), "end") --執行代碼,coroutine狀態爲running --->(4)
end)
print(coroutine.status(co)) --剛創建的coroutine的狀態爲suspend --->(1)
coroutine.resume(co, 1, 2) --啓動coroutine,將跳轉到coroutine的function執行 --->(2)
print(coroutine.status(co)) --coroutine執行完畢,狀態爲dead --->(5)
代碼的執行結果如下:
suspended
running start
co 1 2
running end
dead
4.yield對coroutine流程的干預
yield作用是將一個running的coroutine掛起,相應的其狀態就會被切換成suspend。在執行到yield之後,代碼跳轉到上一次resume代碼的後一條代碼執行,再次調用resume,代碼就跳轉到上一次yield代碼的後一條代碼執行。一般來說,resume方法在主線程中調用;而yield則是coroutine內調用,包括coroutine內部調用的函數內部。在coroutine中調用resume沒有什麼問題,但這樣是沒有什麼意義的,因爲如果代碼還在coroutine中執行的話,則說明其狀態一定是running的,這個時候的resume是沒有任何意義的。而在主線程中調用yield,會導致 “lua: attempt to yield across metamethod/C-call boundary”的錯誤。
co = coroutine.create(function(a, b)
print(coroutine.status(co), "start") --->(2)
for i = 1, 10 do
print("co", a, b) --->(3)(6)
coroutine.yield()
print(coroutine.status(co), "after yield") --->(5)
end
print(coroutine.status(co), "end")
end)
print(coroutine.status(co)) --->(1)
coroutine.resume(co, 1, 2)
print(coroutine.status(co)) --->(4)
coroutine.resume(co, 1, 2)
print(coroutine.status(co)) --->(7)
執行結果
suspended
running start
co 1 2
suspended
running after yield
co 1 2
suspended
5.resume,
function()以及yield之間的參數傳遞和返回值傳遞
resume的參數除了coroutine句柄(第一個參數)以外,都傳遞給了function,關係跟表達式賦值是一致的,少的以nil補足,多的捨棄。
co1 = coroutine.create(function(a, b)
print("co", a, b)
end)
co2 = coroutine.create(function(a, b)
print("co", a, b)
end)
co3 = coroutine.create(function(a, b)
print("co", a, b)
end)
coroutine.resume(co1, 1)
coroutine.resume(co2, 1, 2)
coroutine.resume(co3, 1, 2, 3)
執行結果如下:
co1nil
co 1 2
co 1 2
如果在coroutine中包含有yield,情況會複雜一些。
我們進一步挖掘coroutine的流程:
1 resume
2 function
3 yield
4 yield掛起,第一次 resume返回
5 第二次resume
6 yield返回
7 function 繼續執行
在這個流程的第一步的時候,resume的參數會傳遞給function,作爲參數(具體如上);到了第三步的時候,yield的參數會作爲resume返回值的一部分;而第二次resume(第五步)的時候,resume的參數的作用發生了改變,resume的參數會傳遞給yield,做爲yield的返回值。
這個過程很精巧,在coroutine執行的過程中返回,必然需要告訴外部現在coroutine這個時候的內部的的情況,通過唯一的接口yield的參數作爲resume的返回值,高;到了第二次resume的時候,外部的環境必然發生了改變, 怎麼通知coroutine內部呢,同樣的想法,將唯一的接口resume的參數通過yield的返回的途徑返回到coroutine內部,一樣的高明。
貼一個引用的代碼
function foo (a)
print("foo", a) -- foo 2
return coroutine.yield(2 * a) -- return: a , b
end
co = coroutine.create(function (a , b)
print("co-body", a, b) -- co-body 1 10
local r = foo(a + 1)
print("co-body2", r)
local r, s = coroutine.yield(a + b, a - b)
print("co-body3", r, s)
return b, "end"
end)
print("main", coroutine.resume(co, 1, 10)) -- true, 4
print("------")
print("main", coroutine.resume(co, "r")) -- true 11 -9
print("------")
print("main", coroutine.resume(co, "x", "y")) -- true 10 end
print("------")
print("main", coroutine.resume(co, "x", "y")) -- false cannot resume dead coroutine
print("------")
結果如下:
co-body 1
10
foo 2
main true
4
------
co-body2 r
main true
11 -9
------
co-body3 x
y
main true
10 end
------
main false
cannot resume dead coroutine
------