如何将Lua流水账1:协同改写为一个长尾词的?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1332个文字,预计阅读时间需要6分钟。
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();
本文共计1332个文字,预计阅读时间需要6分钟。
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();

