lua中的協程

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()
相關文章
相關標籤/搜索