6

我想下载一个大文件并同时处理其他事情。

但是,luasocket.http从不调用coroutine.yield(). 文件下载时,其他所有内容都会冻结。

这是一个说明性示例,我尝试同时下载文件并打印一些数字:

local http = require'socket.http'

local downloadRoutine = coroutine.create(function ()
    print 'Downloading large file'
    -- Download an example file
    local url = 'http://ipv4.download.thinkbroadband.com/5MB.zip'
    local result, status = http.request(url)
    print('FINISHED download ('..status..', '..#result..'bytes)')
end)

local printRoutine = coroutine.create(function ()
    -- Print some numbers
    for i=1,10 do
        print(i)
        coroutine.yield()
    end
    print 'FINISHED printing numbers'
end)

repeat
    local printActive = coroutine.resume(printRoutine)
    local downloadActive = coroutine.resume(downloadRoutine)
until not downloadActive and not printActive
print 'Both done!'

运行它会产生这个:

1
Downloading large file
FINISHED download (200, 5242880bytes)
2
3
4
5
6
7
8
9
10
FINISHED printing numbers
Both done!

如您所见,printRoutineresumed 首先。它打印数字 1 和yields。然后downloadRoutineresumed,它下载整个文件,而不产生. 只有这样才能打印其余的数字。

我不想编写自己的套接字库!我能做些什么?

编辑(同一天晚些时候):一些 MUSH 用户也注意到了。他们提供有用的想法。

4

2 回答 2

5

我不明白为什么您不能使用PiL 建议copas 库(这与此处给出的答案几乎相同)。

Copas 包装了套接字接口(不是socket.http),但你可以使用低级接口来获得你需要的东西(未经测试):

require("socket")
local conn = socket.tcp()
conn:connect("ipv4.download.thinkbroadband.com", 80)
conn:send("GET /5MB.zip HTTP/1.1\n\n")
local file, err = conn:receive()
print(err or file)
conn:close()

然后,您可以使用addthreadfrom copas 为您提供一个非阻塞套接字,并在有东西要接收时使用step/loop函数来执行。receive

使用 copas 的工作量更少,而settimeout(0)直接使用则为您提供更多控制权。

于 2012-11-12T22:33:41.683 回答
2

协程不是线程;他们是合作的,而不是同时的。当一个协程屈服于另一个协程时,它就会被阻塞。vanilla Lua 中不能有两个同时执行的指针。

但是,您可以使用外部库来实现该效果。最受欢迎的之一是Lua Lanes

于 2012-11-11T22:07:34.130 回答