1. 程式人生 > >淺談Lua的Coroutine-協程的多"執行緒"併發模型

淺談Lua的Coroutine-協程的多"執行緒"併發模型

看了一下《Programming in Lua》裡的協程程式的運用,總覺得有點像霧裡看花一樣,捉不到重點,不知道怎麼去運用,但在洗澡時靈光一閃,突然想明白了這不只是使用了Reactor(反應時同步時間分派)模式嗎。在這裡寫篇部落格跟大家分享一些拙見。

先貼一下之前看得不怎麼懂的原始碼

function download (host, file)          -->協同程式
    local c = assert(socket.connect(host, 80))
    local count = 0 -- counts number of bytes read
    c:send("
GET " .. file .. " HTTP/1.0\r\n\r\n") while true do local s, status = receive© count = count + string.len(s) if status == "closed" then break end end c:close() print(file, count) end function receive (connection) -->我把它叫做"中斷程式" connection:timeout(0
) --> do not block local s, status = connection:receive(2^10) if status == "timeout" then coroutine.yield(connection) end return s, status end threads = {} --> list of all live threads function get (host, file) --> 工廠函式 local
co = coroutine.create(function () download(host, file) end) table.insert(threads, co) --> insert it in the list end function dispatcher () -->分派器函式 while true do   local n = table.getn(threads)   if n == 0 then break end     for i=1,n do       local status, res = coroutine.resume(threads[i])       if not res then           table.remove(threads, i)         break       end     end   end end

首先來看一下

  dispatcher函式實際上充當了Reactor模式中的select和poll/epoll

  get這個工廠函式充當了向分派器註冊“執行緒”(協同程式)的作用

  download與receive這兩個函式在Reactor模式中共同起到一個執行緒的作用

  不同點是:1、以上Lua程式碼中通過額外的恢復/掛起操作代替了Reactor模式中的分派器檢測系統資源來確定執行緒是否活動

       2、因為分派器與各“執行緒”(協同程式)的執行實際上都在一個執行緒中執行,不能利用系統在真正執行緒之間分時切換,必須手動實現切換。

  Coroutine-協程模型的優點是:

       1、切換上下文的代價比較小。

       2、不需要考慮同步問題。  

實際上按照Reactor模式使用多協程程式很簡單

  只需要實現一個全域性的分派器,開放註冊“執行緒”的介面。寫需要的協同程式(必須包含一箇中斷條件),並註冊到分派器。

  執行分派器就可以實現簡單的多執行緒併發。當然這只是一個最簡單的模型,只能在當至少有一個“執行緒”有資料可讀取的時候執行比較良好,如果各個“執行緒”都處於空閒狀態,則分配器會不斷輪詢執行緒狀態,導致消耗大量時間。