標籤:
多線程和協程
多線程是搶佔式多任務(preemptive multitasking),每個子線程由作業系統來決定何時執行,由於執行時間不可預知所以多線程需要使用同步技術來避免某些問題。在單核電腦中,同一時刻只有一個線程允許運行,而在多核電腦中,同一時刻可以有多個線程同時運行(比如8核CPU就可以最多讓8個線程同時運行)。
協程是協作式多任務(cooperative multitasking),它把決定權交給任務,讓它們在自己認為合適的時候自願放棄執行。協程不是多線程,無論是幾核CPU,同一時刻都只會有一個協程在運行。
有意思的是主流的程式語言(如C++、Java、Pascal等)裡我們很少能看到協程的身影,但是現在不少動態指令碼語言(Lua、Python、Perl)卻都提供了協程或與之相似的機制。
Lua本身不支援多線程的,不同線程共用一個State會出問題,但是支援協程。
Lua協程
官方文檔:http://www.lua.org/manual/5.2/manual.html#6.2
最簡單的樣本
下面我們來看一個簡單的樣本:
1 --建立一個協程對象, 傳入的參數為該協程啟動並執行主函數 2 co = coroutine.create( 3 function() 4 print("step 1") 5 coroutine.yield() 6 print("step 2") 7 coroutine.yield() 8 print("step 3") 9 end10 )11 12 --運行協程13 print(coroutine.status(co))14 coroutine.resume(co)15 print("main thread code 1")16 --運行協程17 print(coroutine.status(co))18 coroutine.resume(co)19 print("main thread code 2")20 --運行協程21 print(coroutine.status(co))22 coroutine.resume(co)23 print("main thread code 2")24 25 print(coroutine.status(co))
我們先看下啟動並執行結果:
1 suspended 2 step 1 3 main thread code 1 4 suspended 5 step 2 6 main thread code 2 7 suspended 8 step 3 9 main thread code 210 dead
我們可以發現,在協程中遇到coroutine.yield()時,該協程的運行會被暫停這時主線程會繼續運行,直到調用coroutine.resume方法時對應的協程才會繼續運行。當協程的方法運行完畢時該協程也就結束了,state為dead。
帶參數和返回的協程
協程是可以帶有參數和傳回值的,如下:
1 --建立一個協程對象, 傳入的參數為該協程啟動並執行主函數 2 co = coroutine.create( 3 function(a, b, c) 4 local i = 0 5 print("add", "add", "i:", i) 6 i = 10 7 coroutine.yield(a + b, b + c) 8 print("add", "sub", "i:", i) 9 i = 10010 coroutine.yield(a + b, b - c)11 print("sub", "sub", "i:", i)12 i = 100013 coroutine.yield(a - b, b - c)14 print("i:", i)15 end16 )17 18 --運行協程19 state, result1, result2 = coroutine.resume(co, 10, 5, 3)20 print(state, result1, result2)21 --運行協程22 state, result1, result2 = coroutine.resume(co, 100, 50, 30)23 print(state, result1, result2)24 --運行協程25 state, result1, result2 = coroutine.resume(co, 1000, 500, 300)26 print(state, result1, result2)27 28 coroutine.resume(co)
運行結果如下:
1 add add i: 02 true 15 83 add sub i: 104 true 15 25 sub sub i: 1006 true 5 27 i: 1000
我們看看協程參數和傳回值要注意的一點地方:
- 參數只有第一次調用時傳入有效,後面調用resume傳入的參數會被忽略;
- 傳回值的第一個值為調用是否成功的一個布爾值,如果成功則後跟返回的參數,如果失敗則後跟報錯的資訊;
Lua學習筆記(六):協程