2012-11-11 6 views
5

Voglio scaricare un file di grandi dimensioni e gestire contemporaneamente altre cose.Come faccio a gestire le librerie Lua che non fanno coroutine.yield()?

Tuttavia, luasocket.http non chiama mai coroutine.yield(). Tutto il resto si blocca mentre il file viene scaricato.

Ecco un esempio illustrativo, in cui cerco di scaricare contemporaneamente un file e stampare alcuni numeri:

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

esecuzione produce questo:

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

Come si può vedere, printRoutine è resume d prima. Stampa il numero 1 e yield s. Il downloadRoutine è quindi resume d, che scarica l'intero file, senza produrre. Solo allora vengono stampati i restanti numeri.

Non voglio scrivere la mia libreria di socket! Cosa posso fare?

Modifica (più tardi lo stesso giorno): Alcuni utenti MUSH have also noticed. Forniscono idee utili.

+1

Le coroutine non sono thread. Non dovresti trattarli come fili. Se un processo non vuole cedere, allora non lo farà, e non puoi * forzarlo * a cedere. LuaSocket ha alcune funzionalità per IO non bloccanti, ma non ho molta familiarità con LuaSocket, quindi dovrai investigarle. –

+1

LuaSocket supporta operazioni asincrone (ovvero non bloccanti). RTFM prima di riscrivere la libreria. – Mud

+3

Fango: Sì, lo "zoccolo" grezzo lo fa. Ma 'socket.http' no. (Vedi http://www.mail-archive.com/[email protected]/msg04969.html.) – Anko

risposta

5

Non vedo perché non è possibile utilizzare PiL advice o copas library (questa è quasi la stessa risposta di here).

Copas avvolge l'interfaccia socket (non socket.http), ma è possibile utilizzare l'interfaccia a basso livello per ottenere quello che ti serve con qualcosa di simile (non testato):

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

È quindi possibile utilizzare addthread da copas a Dare un socket non bloccante e utilizzare le funzioni step/loop per fare receive mentre c'è qualcosa da ricevere.

L'uso di copas è meno efficace, mentre l'utilizzo di settimeout(0) offre un maggiore controllo.

+0

Grazie per le utili alternative! Questo risolve il mio problema specifico. La mia * domanda * è più generale però: molte altre librerie, come 'ssl.https' di LuaSec (non banale da ri-implementare) sono ancora sincrone ... – Anko

+0

Buon punto, anche se potresti ancora essere in grado di fare lo stesso cosa con ssl.https.In effetti, l'esempio che ho dato è una versione semplificata del mio esempio con ssl.https (http://notebook.kulchenko.com/programming/https-ssl-calls-with-lua-and-luasec). Detto questo, non sono sicuro che 'ssl.https' funzioni allo stesso modo con settimeout (0) in quanto non ho avuto la possibilità di testarlo. –

2

Le coroutine non sono fili; sono cooperativi, non simultanei. Quando una coroutine cede a/da un altro, viene bloccata. Non puoi avere due puntatori di esecuzione simultanei in vanilla Lua.

Tuttavia, è possibile utilizzare librerie esterne per questo effetto. Uno dei più popolari è Lua Lanes.

+0

Riscrivere 'socket.http' per cedere più spesso sembra facile in confronto. Ma per aggirare un pezzo più grande del codice della libreria di blocco, sarebbe un grande trucco! – Anko

Problemi correlati