On Mon, 19 Mar 2007 12:04:20 +0100 (CET), Daniele Varrazzo <[EMAIL PROTECTED]> 
wrote:
Come già spiegato anche da Valentino, non sempre "multithreading" implica
"più veloce". Ma nel tuo caso è così, caschi bene :)

Beh no, dissento profondamente. Quantomeno e` veloce uguale, in python e` solo 
piu` lento.
Secondariamente in questo caso usi un quantitativo di ram proibitivo per fare 
poco o nulla e il
codice risultante e` incredibilmente piu` complesso di quelle 20 righe che ho 
scritto che facilmente si possono riadattare a fare il crawler.

In fondo al messaggio attacco uno script che avevo scritto un po' di tempo
fa: usa diversi thread per scaricare una serie di file. Non è uno spider
perché la lista di cose da scaricare va specificata all'inizio, ma penso sia
chiara la modifica da effettuare: quando un'istanza di Job trova una url
"interessante", deve aggiungerla alla lista "DownloadManager.urls" dei
compiti da svolgere. Dovresti modificare la signature di Job.__init__ in
modo che possa ricevere un puntatore a tutto il download manager (che nome
borioso!) anziché al solo callback che notifica dell'avvenuto download: io
aggiungerei un metodo DownloadManager.add_job(...) che aggiunga il nuovo job
alla lista rispettando il lock.

Cosi` a naso direi che il tuo codice contiene almeno una race condition che 
solo casualmente
non hai mai incontrato nella vita reale.

Infatti il loop nell'__init__ del download manager usa: url, filename = 
self.urls.pop()
senza pero` acquisire e rilasciare il lock su urls. Questo significa che se un 
download
finisce prima che possa terminare questo loop abbiamo almeno due risorse che 
accedono
contemporaneamente a quella variabile e chissa` cosa succede :). Sistemarlo e` 
banale,
tuttavia in 100 righe di codice molto semplice e con un solo lock da gestire 
c'e` stato
spazio per una race condition, cosi` facile non deve essere.

Spero ti serva di "ispirazione": ci ho messo pochi minuti a scriverlo, ha
fatto il suo porco lavoro e in effetti il fatto che in Python si scriva un
download manager multi-thread in meno di 100 righe fa la sua figura :)

Se togliamo la race condition, forse.

E` proprio una questione architetturale: con il multi-threading l'esecuzione e` 
al massimo
veloce uguale e in rari casi e neanche troppo frequenti. Il multi processing e` 
_sempre_ piu` veloce (e raramente anche linearmente piu` veloce) nei casi in 
cui si puo` applicare (posto che il tempo di startup di un processo e` piu` 
elevato rispetto a quello di un thread in molte architetture). Entrambi 
occupano piu` risorse dello stretto indispensabile. Come anche Ludo potrebbe 
facilmente mostrare (senza usare Twisted) e` abbastanza semplice ottenere un 
client http asincrono estremamente veloce.

Essere asincroni permette di non sprecare inutilmente risorse, permette di 
essere molto piu` veloci (si possono gestire con pochissimi problemi di 
scalabilita` un numero esagerato di client essendo quindi piu` veloci a 
scaricare le pagine), permette di evitare i problemi di locking. Inoltre, ma 
questo
piu` che altro riguarda python, si possono sfruttare efficacemente i 
multi-processori avviando piu`
processi di questo crawler asincrono che lavorano su due sezioni (o in altro 
modo analogo) della
lista degli url di partenza per poi farsi il proprio giretto nella rete 
sfruttando al 100% processori
multipli. Esistono situazioni in cui il multi-threading e` utile (al di la` del 
kernel level) ma per tutto il resto questi risultano essere semplicemente 
un'astrazione sbagliata, specialmente se, come nel tuo script, sono usati con 
shared state invece che con message passing attraverso le Queue.
_______________________________________________
Python mailing list
Python@lists.python.it
http://lists.python.it/mailman/listinfo/python

Rispondere a