当前位置 : 主页 > 网络编程 > lua >

lua流水账1:协同

来源:互联网 收集:自由互联 发布时间:2021-06-23
1.协同程序 不对称的协同:挂起一个正在执行的协同的函数(coroutine.yield())与使一个被挂起的协同再次执行的函数(coroutine.resume())是不同的。 Lua提供的协同是不对称的协同 知道4个函数

1.协同程序
不对称的协同:挂起一个正在执行的协同的函数(coroutine.yield())与使一个被挂起的协同再次执行的函数(coroutine.resume())是不同的。
Lua提供的协同是不对称的协同
知道4个函数的使用:coroutine.create(function):创建一个协同,coroutine.yield():挂起一个协同,coroutine.resume(thread):执行一个协同,coroutine.status(thread):查询一个协同的状态。
特征:可以不断地颠倒调用者和被调用者之间的关系。
例1:

--创建一个协同程序
local co = coroutine.create(function () print("this is coroutine") end);
print(co);
--输出协同状态,有3种状态:挂起态,运行态,停止态
print(coroutine.status(co));
--将程序从挂起态变为运行态
coroutine.resume(co);
print(coroutine.status(co));
输出:
thread: 02AEC138
suspended
this is coroutine
dead

例2:

local co = coroutine.create(function ()
    for i = 0,2 do
        print("co"..i);
        --将协同程序挂起
        coroutine.yield()
    end
end);
print(coroutine.status(co));
coroutine.resume(co);
print(coroutine.status(co));
coroutine.resume(co);
print(coroutine.status(co));
coroutine.resume(co);
--注意resume运行在保护模式下,如果协同内部存在错误Lua并不会抛出错误
--而是将错误放回给resume函数
print(coroutine.status(co));
print(coroutine.resume(co));
print(coroutine.status(co));
print(coroutine.resume(co));
print(coroutine.status(co));
输出:
suspended
co0
suspended
co1
suspended
co2
suspended
true
dead
false   cannot resume dead coroutine
dead

例3:

local co = coroutine.create(function (a,b) print("co",a,b) end);
coroutine.resume(co,10,20);
输出:1020
local co = coroutine.create(function (a,b) print("co",a,b) end);
print(coroutine.resume(co,10,20));
输出: true

例4:

local co = coroutine.create(function (a,b)
    coroutine.yield(a,b)
    end);
local status,a, b = coroutine.resume(co,10,20);
print(status,a,b);
输出:true 10  20
local co = coroutine.create(function (a,b)
    coroutine.yield(a,b)
    end);
print(coroutine.resume(co,10,20));
输出:true 10  20

例5:

local co = coroutine.create(function()
    print("co",coroutine.yield());
end)
print(coroutine.status(co));
coroutine.resume(co);
print(coroutine.status(co));
coroutine.resume(co,4,5);
print(coroutine.status(co));
输出:
suspended
suspended
co  4   5
dead

例6:

local co = coroutine.create(function() return 6,7 end);
local status,a,b = coroutine.resume(co);
print(status,a,b);
输出:true 6   7
local co = coroutine.create(function() return 6,7 end);
print(coroutine.resume(co));
输出:true 6   7

例7:生产者消费者问题

function consumer()
    while true do
        local x = receive();
        io.write(x,"\n");
    end
end
function receive()
    local status,value = coroutine.resume(producer);
    return value;
end
producer = coroutine.create(function()
    while true do
        local x = io.read();
        coroutine.yield(x);
    end
end)
consumer();
function receive(prod)
    local status,value = coroutine.resume(prod);
    return value;
end

function send(x)
    coroutine.yield(x);
end

function producer()
    return coroutine.create(function()
        while true do
            local x = io.read();
            send(x);
        end
    end);
end

function filter(prod)
    return coroutine.create(function()
        local line = 1;
        while true do
            local x = receive(prod);
            x = string.format("%5d %s",line,x);
            send(x);
            line = line + 1;
        end
    end);
end

function consumer(prod)
    while true do
        local x = receive(prod);
        io.write(x,"\n");
    end
end

p = producer();
f = filter(p);
consumer(f);

例8:迭代器实现

function permgen(a,n)
    if n == 0 then
        printResult(a);
    else
        for i = 1,n do
            a[n],a[i] = a[i],a[n];
            permgen(a,n-1);
            a[n],a[i] = a[i],a[n]
        end
    end
end

function printResult(a)
    for i,v in ipairs(a) do
        io.write(v," ");
    end
    io.write("\n");
end

permgen({1,2,3,4},4);
function permgen(a,n)
    if n == 0 then
        coroutine.yield(a);
    else
        for i = 1,n do
            a[n],a[i] = a[i],a[n];
            permgen(a,n-1);
            a[n],a[i] = a[i],a[n]
        end
    end
end

function perm(a)
    local n = table.getn(a);
    local co = coroutine.create(function() permgen(a,n) end)
    return function()
        local code,res = coroutine.resume(co);
        return res;
    end
end

function printResult(a)
    for i,v in ipairs(a) do
        io.write(v, " ");
    end
    io.write("\n");
end

for p in perm{"a","b","c"} do
    printResult(p);
end

其中wrap创建一个协同程序,但是wrap不返回协同本身,而是返回一个函数,当这个函数被调用时将resume协同。wrap中resume协同的时候不会返回错误代码作为第一个返回结果,一旦有错误发生,将抛出错误。

function permgen(a,n)
    if n == 0 then
        coroutine.yield(a);
    else
        for i = 1,n do
            a[n],a[i] = a[i],a[n];
            permgen(a,n-1);
            a[n],a[i] = a[i],a[n]
        end
    end
end

function perm(a)
    local n = table.getn(a);
    return coroutine.wrap(function() permgen(a,n) end)
end

function printResult(a)
    for i,v in ipairs(a) do
        io.write(v, " ");
    end
    io.write("\n");
end

for p in perm{"a","b","c"} do
    printResult(p);
end

非抢占式多线程:不管什么时候只要有一个线程调用一个阻塞操作,整个程序在阻塞操作完成之前都将停止。对大部分应用程序而言,是无法忍受的,下面是这个问题的解决方案:

require "luasocket"

function download(host,file)
    local c = assert(socket.connent(host,80));
    local count = 0;
    c:send("GET "..file.." HTTP/1.0\r\n\r\n");
    while true do
        local s,status = receive(c);
        count = count + string.len(s);
        if status == "closed" then break end
    end
    c:close();
    print(file,count);
end

function receive(connection)
    connection:timeout(0);
    local s,status = connection:receive(2^10);
    if status == "timeout" then
        coroutine.yield(connection);
    end
    return s,status;
end

threads = {};
function get(host,file)
    local co = coroutine.create(function()
        download(host,file)
    end)
    table.insert(threads,co);
end

function dispatcher()
    while true do
        local n = table.getn(threads);
        if n == 0 then break end
        local connections = {};
        for i = 1,n do
            local status,res = coroutine.resume(threads[i]);
            if not res then    --thread finished its task
                table.remove(threads,i);
                break;
            else                --timeout
                table.insert(connections,res);
            end
        end
        if table.getn(connections) == n then
            socket.select(connections);
        end
    end
end

host = "www.w3c.org"
get(host,"/TR/html401/html40.txt");
get(host,"/TR/2002/REC-xhtml1-20020801/xhtml1.pdf");
get(host,"TR/REC-html32.html");
get(host,"/TR/2000/REC-DOM-Level-2-Core-20001113/DOM2-Core.txt");
dispatcher();
网友评论