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);
输出:10,20
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();