2012-11-11 5 views
5

Ich möchte eine große Datei herunterladen und gleichzeitig andere Dinge behandeln.Wie gehe ich mit Lua-Bibliotheken um, die nicht coroutine.yield() enthalten?

Jedoch ruft luasocket.http nie coroutine.yield(). Alles andere friert beim Herunterladen der Datei ein.

Hier ist ein anschauliches Beispiel, in dem ich versuche, gleichzeitig eine Datei herunterzuladen und einige Zahlen drucken:

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!' 

Laufen sie dies erzeugt:

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

Wie Sie sehen können, printRoutine ist resume d zuerst. Es druckt die Nummer 1 und yield s. Die downloadRoutine ist dann resume d, die die gesamte Datei herunterlädt, ohne zu ergeben. Nur dann werden die restlichen Zahlen gedruckt.

Ich möchte nicht meine eigene Socket-Bibliothek schreiben! Was kann ich tun?

Bearbeiten (später am selben Tag): Einige MUSH-Benutzer have also noticed. Sie bieten hilfreiche Ideen.

+1

Coroutines sind keine Threads. Sie sollten sie nicht wie Fäden behandeln. Wenn ein Prozess nicht nachgeben will, dann wird er es nicht tun, noch kann er es erzwingen. LuaSocket bietet einige Möglichkeiten für nicht blockierendes IO, aber ich kenne LuaSocket nicht sehr gut, daher müssen Sie sie untersuchen. –

+1

LuaSocket unterstützt asynchrone (d. H. Nicht blockierende) Operationen. RTFM vor dem Umschreiben der Bibliothek. – Mud

+3

Mud: Ja, die rohe "Socket" tut. Aber 'socket.http' nicht. (Siehe http://www.mail-archive.com/[email protected]/msg04969.html.) – Anko

Antwort

5

Ich sehe nicht, warum Sie PiL advice oder copas library nicht verwenden können (das ist fast die gleiche Antwort wie here gegeben).

Copas wickelt die Socket-Schnittstelle (nicht socket.http), aber Sie können niedrige Level-Schnittstelle verwenden zu bekommen, was man mit so etwas wie dieses benötigen (nicht getestet):

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() 

Sie dann addthread von copas verwenden können, um Geben Sie einen nicht blockierenden Socket und verwenden Sie step/loop Funktionen, receive zu tun, während es etwas zu empfangen gibt.

Mit Copas ist weniger Arbeit, während die Verwendung settimeout(0) direkt gibt Ihnen mehr Kontrolle.

+0

Danke für die hilfreichen Alternativen! Das löst mein spezifisches Problem. Meine * Frage * ist jedoch allgemeiner: Viele andere Bibliotheken, wie LuaSec'sls.https' (nicht-trivial zu re-implementieren) sind immer noch synchron ... – Anko

+0

Guter Punkt, obwohl Sie vielleicht immer noch dasselbe tun können was mit ssl.https.In der Tat ist das Beispiel, das ich gab, eine vereinfachte Version meines Beispiels mit ssl.https (http://notebook.kulchenko.com/programming/https-ssl-calls-with-lua-and-luasec). Nachdem ich das gesagt habe, bin ich nicht sicher, ob "ssl.https" mit settimeout (0) genauso funktioniert, wie ich es noch nicht testen konnte. –

2

Coroutines sind keine Threads; sie sind kooperativ, nicht gleichzeitig. Wenn eine Coroutine zu einer anderen kommt, wird sie blockiert. Sie können in Vanilla Lua nicht zwei Ausführungszeiger gleichzeitig ausführen.

Sie können jedoch externe Bibliotheken zu diesem Zweck verwenden. Einer der beliebtesten ist Lua Lanes.

+0

Das Umschreiben von 'socket.http', um öfter auszugeben, scheint im Vergleich einfach. Aber um ein größeres Stück blockierenden Bibliothekscode zu bearbeiten, wäre das ein großartiger Hack! – Anko