咱們一塊兒來學lua:協程(coroutine) 四

今天咱們先來看下lua手冊上一個協程實例:異步

手冊實例:
function foo(a)
    print("foo", a)
    return coroutine.yield(2 * a)
end

co = coroutine.create(function ( a, b )
    print("co-body", a, b)
    local r = foo(a + 1)
    print("co-body", r)
    local r, s = coroutine.yield(a + b, a - b)
    print("co-body", r, s)
    return b, "end"
end)

print("main", coroutine.resume(co, 1, 10))
print("main", coroutine.resume(co, "r"))
print("main", coroutine.resume(co, "x", "y"))
print("main", coroutine.resume(co, "x", "y"))
執行結果:
co-body    1    10        -- 協程co的第7行,此時resume()傳入的參數是賦值給了函數的
foo    2            -- 在第8行裏面調用了函數foo(),執行到第2行的打印
main    true    4        -- 因爲函數foo()的第3行yield()執行後掛起,參數是4,做爲第15行的resume()的第二個返回值,最終打印了出來,到此,第15行執行完畢
co-body    r            -- 第16行resume()再次喚醒協程co,接着上次yield()的地方繼續執行,參數「r"被賦值給上次yield()的返回值,在第9行打印出來
main    true    11    -9    -- 在第10行yiled()後再次掛起協程co,並返回,此時參數a和b仍是第一次resume()時的參數,1,10,因此yield()兩個參數分別爲11,-9,做爲resum()的第二個返回值,最終被打印出來,到此,第16行執行完畢
co-body    x    y        -- 第17行resume()再次喚醒協程co,傳入的參數「x」,「y」被賦值給上次的yield()函數的返回值,即賦值給第10行的r,s,在第11行被打印出來
main    true    10    end    -- 協程co在第12行返回,注意此時參數b仍然是第一次resume()時的參數2,值爲10,至此協程co執行結束,變爲dead狀態,最終在第17行打印出來
main    false    cannot resume dead coroutine -- 第18行嘗試再次resume()協程co,因爲協程co已經爲dead狀態,因此直接返回並報錯

上面這個實例很好的展現了coroutine.yield和coroutine.resume之間的相互做用。協程在生產者和消費者問題上應用也比較普遍,咱們來看看下面這個例子。函數

生產者與消費者:
coConsume = coroutine.create(
    function ()
        while true do
            local stutas, msg = coroutine.resume(coProducer)
            print('receive msg : ', msg)
            coroutine.resume(coProducer, string.len(msg))
        end
    end
)

coProducer = coroutine.create(
    function ()
        while true do
            local msg = io.read()
            local len = coroutine.yield(msg)
            print('he tell me he has recved data len is ', len)
            coroutine.yield()
        end
    end
)
coroutine.resume(coConsume)
運行結果:
hello         --從鍵盤輸入
receive msg :     hello
he tell me he has recved data len is     5

上面這個實例有兩個協程,一個是生產協程主要是從屏幕上接收輸入的數據,另一個是消費協程,處理接收到的信息將其打印。性能

總結:

最後引用知乎上的一段話做爲協程學習的一個小結。
在IO密集型的程序中因爲IO操做遠遠小於CPU的操做,因此每每須要CPU去等IO操做。同步IO下系統須要切換線程,讓操做系統能夠在IO過程當中執行其餘的東西。這樣雖然代碼是符合人類的思惟習慣可是因爲大量的線程切換帶來了大量的性能的浪費,尤爲是IO密集型的程序。學習

因此人們發明了異步IO。就是當數據到達的時候觸發個人回調。來減小線程切換帶來性能損失。可是這樣的壞處也是很大的,主要的壞處就是操做被 「分片」 了,代碼寫的不是 「一鼓作氣」 這種。 而是每次來段數據就要判斷 數據夠不夠處理哇,夠處理就處理吧,不夠處理就在等等吧。這樣代碼的可讀性很低,其實也不符合人類的習慣。lua

可是協程能夠很好解決這個問題,好比 把一個IO操做 寫成一個協程。當觸發IO操做的時候就自動讓出CPU給其餘協程。要知道協程的切換很輕的。協程經過這種對異步IO的封裝 既保留了性能也保證了代碼的 容易編寫和可讀性。在高IO密集型的程序下很好,可是高CPU密集型的程序下沒啥好處。操作系統

相關文章
相關標籤/搜索