[Python] Applicazione multithreading

Valentino Volonghi aka Dialtone dialtone a divmod.com
Lun 19 Mar 2007 22:47:16 CET


On Mon, 19 Mar 2007 13:36:42 +0100 (CET), Daniele Varrazzo <piro a develer.com> wrote:

>Allora, de-dissenti, questa volta :) Se non ci credi, metti 1000 url in
>questa lista, e lanciala con MAX_THREAD prima a 1, poi a 10. Vedrai che c'è
>differenza.

>La differenza c'è perché la cosa più lenta è la rete, che nel mio caso
>poteva essere sfruttata meglio. Avevo 1000 file da scaricare e mentre andava
>un file alla volta vedevo col firewall personale che non facevo più di (boh,
>metti) 10k/sec. Con la versione multithread ho sfruttato tutta la banda
>disponibile e ho finito in una frazione del tempo (minuti anziché ore).

Manlio ha gia` risposto piu` che esaurientemente a questa domanda. Non esiste solo il 
multi-threading per l'IO (anzi... meglio non usare il multi-threading per i problemi di IO).

>> Quantomeno e` veloce uguale, in python e`
>> solo piu` lento.
>
>Se eseguisse bytecode di continuo sarebbe così. Ma il collo di bottiglia è
>il read, che probabilmente è una chiamata in C che rilascia il GIL.

A parte che non e` affatto detto che rilasci il GIL e infatti smtplib ha problemi proprio a riguardo,
resta il fatto che oltre alla read il resto e` eseguito serialmente (sostanzialmente) su un singolo 
processore. Il multithread quindi risulta, come detto, al massimo veloce uguale alla versione a thread
singolo che non e` solo quella seriale ma anche quella asincrona.

>> Secondariamente in questo caso usi un quantitativo di ram proibitivo
>
>dov'è la ram?

Ogni thread alloca come minimo 2MB di stack se non erro (potrebbe essere molto meno). Piu` quello che alloca per i fatti suoi. Moltiplicato per il numero di thread che avii. Decisamente troppa ram buttata via per nulla (e in questo caso "ram is not cheap", visto che evitare di buttarla via e` ancora piu` cheap).

>Quelle si appoggiano su twisted: a quelle 20 righe devi aggiungere
>l'imparare twisted, che non è esattamente una passeggiata. Per te è ovvio
>perché probabilmente mangi pane e twisted, ma non puoi dire che sia facile
>ad una persona che sta imparando il Python ora.

Per quello nel post di risposta originario ho scritto che puo` usare anche pyevent o altri sistemi.
Sarebbe uno spreco di tempo a mio modo di vedere (twisted e` gia` testato e funzionante
anche se il client http/1.1 non e` ancora stato rilasciato, ma c'e`) ma resta tuttavia possibile.

>Ci può essere, perché come detto è uno scriptino usa e getta che doveva fare
>un lavoro una volta e finire lì. Fai bene a puntare il dito verso il
>probabile bug, almeno insegni le rogne di scrivere in multithread.

Si ma andiamo piano. In questo caso la rogna non puo` essere sottovalutata. Infatti il tuo codice
non ha dato il minimo problema per l'uso normale, aumentando la lunghezza degli url da prendere
o accedendo a siti piu` veloci il risultato sarebbe stato imprevedibile (url non scaricati perche` poppati subito dopo essere stati aggiunti o cose simili).
Questo tipo di bachi poi sarebbe stato difficilissimo da scovare e correggere qual'ora quel client
fosse cresciuto in dimensioni e complessita`.

La questione e` proprio tutta li`. Immaginiamo poi di dover integrare quello script con quel piccolo,
ma invisibile, baco in un software piu` grosso e abbiamo una cosa assolutamente invisibile 
difficilissima da riprodurre (sono assolutamente certo che andando di debugger quel baco non si 
mostrerebbe mai ad esempio).

Non e` un problema da poco nonostante, come dici, sia un esempio giocattolo scritto in fretta.
Ti do sicuramente ragione, con piu` cura non ci sarebbe stato nessun problema. Il problema pero`
e` proprio la cura necessaria a scrivere anche un esempietto tanto semplice, figurarsi se e` piu`
grosso. Ecco perche` il multi-threading NON e` la risposta (quasi) MAI.

L'I/O multi-plexing si fa con sistemi asincroni (a eventi o meno) e vanno imparati perche` gli
altri modelli sono sbagliati e in python (in particolare) sono pure sicuramente piu` lenti (perche` 
comunque non sfruttano neanche il multi-core).

>mi prequoto:
>
>>>Spero ti serva di "ispirazione": ci ho messo pochi minuti a scriverlo, ha
>>>fatto il suo porco lavoro
>
>speravo fosse superfluo dire anche "non ho voglia di difendere con le unghie
>e con i denti un lavoro estemporaneo fatto per superare un problema
>estemporaneo ed esplicitamente proposto come tale".

Ma io non sto attando ne` te ne` il tuo lavoro. Coglievo pero` al balzo l'occasione che mi hai dato
mostrando quello che definivi 'semplice esempio' che pero` conteneva un baco definibile nella
categorie degli Heisen Bugs.

>Te l'ho detto: non è stata ottimizzazione preventiva. Quello che dici tu è
>vero fintantoché resti nel bytecode. Ho scritto un programma con codice
>analogo che effettua interrogazioni ad un db ospitato su una macchina
>multiprocessore e con un disco molto veloce. Risultato: con i thread vengono
>processate 8 query contemporaneamente e il tempo totale di processo è pari
>al tempo della più lenta delle query (circa 60 sec) più 1 sec, mentre prima
>era la somma dei tempi. Un incremento di velocità di circa il 500%.

Come sopra: anche coi database si puo` usare l'approcio asincrono o multi processo a seconda
del caso. Anzi (non conosco la velocita` del driver di Manlio) tempo fa esisteva un driver scritto
da jamwt http://jamwt.com/ che interrogava postgres usando Twisted. Questo driver pure-python
era piu` veloce di psycopg2 (fondamentalmente scritto in C a MANO).

>Grazie della discussione: penso sia stata più utile di come hai trattato il
>povero malcapitato in precedenza. Ha sentito parlare di thread, message
>passing, state sharing, lock, race condition, twisted. Ha visto differenze
>di pensiero.

>Anche io sono piuttosto orso il grosso delle volte, però mi sforzo di non
>mangiare vive le persone solo perché ne sanno meno di me. :) Non stiamo
>parlando giusto ora di organizzare un evento finalizzato a far avvicinare
>persone al Python? Penso che dovremo rivolgerci positivamente ai neofiti se
>vogliamo che non fuggano terrorizzati ;)

Beh ma questo non c'entra molto. Non l'ho insultato e neanche preso in giro. Gli ho anche scritto
quello che gli serviva per partire, come hai fatto tu, salvo che lui ha rifiutato di sforzarsi un pochino
cercando piu` che altro una sorta di compitino a casa fatto su quello che lui aveva gia` in mente.
Chiaramente pero` se leggo una persona che chiede come buttarsi giu` da un ponte invece che dirgli
come si fa cerco di fargli capire che ci sono altre strade per risolvere i problemi (estremizzazione 
esagerata per strappare un sorriso). Non e` che piglio a calci nel culo quelli che fanno domande,
in questo caso pero` mi sono sentito abbastanza ignorato nonostante le mie risposte che neanche
sono state lette (per giunta). Pero` quello che mi suona strano e` che mi hai messo nella posizione
di dovermi giustificare di un mio comportamento che non aveva nulla di male solo perche` si sta
organizzando pycon... Invece di giustificarmi diro`:

Un giorno un pover uomo incontra un pescatore di ritorno dalla pesca e gli chiede un pesce. Questi 
gli da` il pesce. Il giorno dopo la scena si ripete. Il terzo giorno la scena si ripete ancora ma questa 
volta il pescatore risponde: "no, io non ti daro` un pesce perche` se lo faccessi domani tornerei e ti 
troverei ancora qua", il pover'uomo: "ma allora io moriro` di fame", il pescatore: "non morirai di fame 
perche` io ti insegnero` a pescare e ti daro` la mia canna da pesca cosi` da ora in poi non avrai piu` 
bisogno di chiedere cibo per la mia strada".

Io penso di avergli dato la canna da pesca.


Maggiori informazioni sulla lista Python