lua中的協程和線程相似:html
1. 協程擁有本身的獨立的棧,局部變量,和指令;多線程
2. 全部協程均可以共享全局變量;socket
3. 協程不能像線程那樣並行執行,協程之間須要相互協調執行,同一個時刻只能運行一個協程;ui
如何使用協程:lua
coroutine.create:建立一個協程,返回一個協程句柄;spa
coroutine.status:查看一個協程的狀態,suspended,running,dead,normal;線程
coroutine.resume:恢復一個協程的執行,若是正常就返回true,錯誤返回false和一條錯誤信息;code
coroutine.yield:掛起一個協程的執行;orm
resume-yield的數據返回:協程
例子:
local co2 = coroutine.create(function(a, b, c)
return coroutine.yield(a + b, b + c, c + a)
end)
print("resume", coroutine.resume(co2, 1, 2, 3)) // 打印 resume true 3 5 4 yield時,返回yield的參數
print("resume", coroutine.resume(co2, 1, 2, 3)) // 打印 resume true 1 2 3 resume時,返回resume的參數
生產者和消費者實例:
以消費者爲驅動,即主循環在消費者,這裏有兩個消費者,同時向一個生產者獲取數據。生產者每產生一個數據就會被掛起,知道下次被消費者激活。
協程程序一旦執行完成,協程狀態就會被設置爲dead,即死亡狀態,若是試圖用resume去激活一個死亡狀態的協程會出現錯誤,能夠經過判斷resume的第一個返回判斷協程運行是否正常。
local producer = coroutine.create(function() local i = 0; while true do i = i + 1; --print(i) coroutine.yield(i) end end) function comsumer_func() local status = 0 data = 0 while true do if (data >= 10) then break end status, data = coroutine.resume(producer) print("comsumer1:", data) coroutine.yield() end end local comsumer1 = coroutine.create(comsumer_func) local comsumer2 = coroutine.create(comsumer_func) local comsumers = coroutine.create(function(...) local threads = {...} local threads_status = {} for i, v in ipairs(threads) do threads_status[i] = true end while true do local status = false for i, v in ipairs(threads) do if (threads_status[i]) then threads_status[i] = coroutine.resume(threads[i]) end status = status or threads_status[i]; end if (not status) then break end end end) print(coroutine.resume(comsumers, comsumer1, comsumer2)) print(coroutine.status(producer)) print(coroutine.status(comsumer1)) print(coroutine.status(comsumer2))
排列組合迭代器實例:
function generate(t, i, n) if (i >= n) then coroutine.yield(t) else for j = i, n do t[j], t[i] = t[i], t[j]; generate(t, i+1, n); t[j], t[i] = t[i], t[j]; end end end function iter(t) local co = coroutine.create(function() generate(t, 1, #t) end) return function() local status, data = coroutine.resume(co) return data end end local t = {"a", "b", "c", "e"} for t in iter(t) do for j = 1, #t do io.write(t[j]) end io.write("\n") end
多線程下載文件實例:
require "socket" function http_get_file(host, file) local con = assert(socket.connect(host, 80)) con:settimeout(0) con:send("GET "..file.." HTTP/1.0\r\n\r\n") print("start to download "..file) while true do local data, status, partial = con:receive(128) io.write(data or partial) if status == "timeout" then --print("timeout") coroutine.yield(con) elseif status == "closed" then print("closed") break end end con:close() end local download_threads = {} function create_download_task(host, file) local thread = assert(coroutine.create(function() http_get_file(host, file) end)) print("thread", thread) table.insert(download_threads, thread) end function start_to_download() local i = 1 while true do if (#download_threads == 0) then break end if (download_threads[i]) then local status, con = coroutine.resume(download_threads[i]) if not con then table.remove(download_threads, i) i = i - 1 end end i = (i + 1) if i > #download_threads then i = 1 end end end create_download_task("news.zol.com.cn", "/591/5916908.html") create_download_task("www.baidu.com", "/") start_to_download()