使用LuaSocket的HTTP模块下载大文件,同时保持用户界面响应

我想使用LuaSocket的HTTP模块来下载一个大文件,并在控制台上以及稍后在GUI中显示进度。即使在传输期间服务器不响应,界面也不能被阻塞。此外,创建一个工作线程来处理下载也不是一个选项。

我已经做了什么:

这里是我到目前为止做的:

local io = io

local ltn12 = require("ltn12")
local http = require("socket.http")

local fileurl = "http://www.example.com/big_file.zip"
local fileout_path = "big_file.zip"

local file_size = 0
local file_down = 0

-- 在ltn12中使用的计数器过滤器
function counter(chunk)
    if chunk == nil then
        return nil
    elseif chunk == "" then
        return ""
    else
        file_down = file_down + #chunk
        ui_update(file_size, file_down) -- 更新 UI,运行主 UI 循环等。
        return chunk -- 返回未修改的块
    end
end

-- 第一次请求
-- 确定文件大小
local r, c, h = http.request {
    method = "HEAD",
    url = fileurl
}
file_size = h["content-length"]

-- 第二次请求
-- 下载文件
r, c, h = http.request {
    method = "GET",
    url = fileurl,
    -- 设置我们的链,先计数再写入文件
    sink = ltn12.sink.chain(
        counter,
        ltn12.sink.file(io.open(fileout_path, "w"))
    )
}

上述代码存在一些问题,忽略错误检查和硬编码:

  1. 它需要 2 个 HTTP 请求,而只有 1 个也可以完成(普通的 GET 请求也会发送 content-length)。
  2. 如果服务器不响应,UI 也将不响应,因为过滤器只在有数据需要处理时才会被调用。

如何确保 UI 不会被阻塞?

点赞
用户1442917
用户1442917

Programming in Lua中有一个非抢占式多线程的例子,使用非阻塞luasocket调用和协程来进行多个并行下载。应该可以将相同的逻辑应用于您的进程以避免阻塞。我只能建议您考虑从GUI中的IDLE事件调用此逻辑(如果有这样的事情),以避免出现“跨元方法/ c-call边界尝试yield”的错误。

2014-06-24 14:54:48