这里介绍一个lua实现多协程下载文件的例子(来源是lua程序设计第四版, 下载链接请私信我, 免费给,csdn传过一次,没通过 )
协程的精髓就在于coroutine.resume的时候从主线程把数据传递给协程(如果是第一次执行,则作为执行函数的参数,之后再执行则作为yield的返回值赋值给上次停止执行的位置的变量), 而执行到coroutine.yield的时候又可以把协程内的数据传递到主线程
1.依赖于luasocket,需要下载编译
- 1.下载源码 git clone https://github.com/diegonehab/luasocket.git
- 2.修改lua版本并编译安装
cd luasocket/src
vi makefile # 将默认的5.1改为你的lua版本
make linux & make install
- 3.验证, 命令中输入lua, 进入lua交互界面, 输入require “socket”,不报错就ok
2.串行下载
local socket = require('socket')
function receive(conn)
local s, status, partial = conn:receive(2^10)
return s or partial, status
end
function getMsTime( )
local now = socket.gettime() * 1000
local tmp1, _ = math.modf(now)
return tmp1
end
function download(host, file)
local startClock = getMsTime()
local c = assert(socket.connect(host, 80))
local count = 0
local request = string.format("GET %s HTTP/1.0\r\nhost: %s \r\n\r\n", file, host)
c:send(request)
while true do
local s, status = receive(c)
count = count + #s
if status == "closed" then
break
end
end
c:close()
local endClock = getMsTime()
print(string.format("file: %s, size: %d, cost: %dms", file, count, endClock - startClock))
end
-- 串行下载文件
local startClock = getMsTime()
print("start download...")
download("www.lua.org", "/ftp/lua-5.3.2.tar.gz")
download("www.lua.org", "/ftp/lua-5.3.1.tar.gz")
download("www.lua.org", "/ftp/lua-5.3.0.tar.gz")
local endClock = getMsTime()
print(string.format("finish download... total cost: %dms ", endClock - startClock))
多协程下载
local socket = require('socket')
function receive(conn)
conn:settimeout(0) -- 设置为非阻塞模式
local s, status, partial = conn:receive(2^10)
if status == "timeout" then
coroutine.yield(conn) -- 把当前的connection传出去
end
return s or partial, status
end
tasks = {}
logfile= io.open("./test.txt","w+")
io.output(logfile)
-- coroutine.wrap和coroutine.create 区别
-- 1.warp调用简单,直接co(param)执行就行,缺点,返回值只有一个(yield返回的值),无法直接从返回值中获取协程的状态
-- 2.create创建的需要配合resume执行,local r1, r2 = coroutine.resume(co, param) r1为布尔值代表执行是否成功,r2为yield返回的值
function corDownload (host, file)
-- 为任务创建协程
local co = coroutine.wrap(function ()
download(host, file)
end)
-- local co = coroutine.create(function ()
-- download(host, file)
-- end)
-- 将任务插入列表
table.insert(tasks, co)
end
-- 协程调度,当执行的的协程返回时,调度另一个协程进行执行,直到所有协程执行结束退出循环
function dispatch ()
local i = 1
while true do
if tasks[i] == nil then
if tasks[1] == nil then
break
end
i = 1
end
local res = tasks[i]() -- 执行一个任务
--local _, res = coroutine.resume(tasks[i]) -- 执行一个任务
if not res then
table.remove(tasks, i)
else
i = i + 1
end
end
end
-- 使用LuaSocket的select,所有协程都没有数据时进入忙等待状态
function dispatchWithSelect ()
local i = 1
timeout = {}
while true do
if tasks[i] == nil then
if tasks[1] == nil then
break
end
i = 1
timeout = {}
end
local res = tasks[i]() -- 执行一个任务
--local _, res = coroutine.resume(tasks[i]) -- 执行一个任务
if not res then
table.remove(tasks, i)
else
i = i + 1
timeout[#timeout + 1] = res
if #timeout == #tasks then -- 所有任务都阻塞
socket.select(timeout)
end
end
end
end
function getMsTime( )
local now = socket.gettime() * 1000
local tmp1, _ = math.modf(now)
return tmp1
end
function download(host, file)
local startClock = getMsTime()
local c = assert(socket.connect(host, 80))
local count = 0
local request = string.format("GET %s HTTP/1.0\r\nhost: %s \r\n\r\n", file, host)
c:send(request)
while true do
local s, status = receive(c)
if status == nil then
status = "nil"
end
io.write(status .. "\n")
count = count + #s
if status == "closed" then
break
end
end
c:close()
local endClock = getMsTime()
print(string.format("file: %s, size: %d, cost: %dms", file, count, endClock - startClock))
end
local startClock = getMsTime()
print("start download...")
corDownload("www.lua.org", "/ftp/lua-5.3.2.tar.gz")
corDownload("www.lua.org", "/ftp/lua-5.3.1.tar.gz")
corDownload("www.lua.org", "/ftp/lua-5.3.0.tar.gz")
dispatch()
local endClock = getMsTime()
print(string.format("finish download... total cost: %dms ", endClock - startClock))