[PIPython] Python & Thread

Alex Martelli aleaxit
Ven 19 Nov 2004 15:16:44 CET


On 2004 Mar 25, at 08:39, Stefano Maniero wrote:

> Salve a tutti, sono un neofita di python e provengo dal mondo java.
>
> Ho qualche dubbio sulla gestione dei thread: ho letto da più parti che 
> python
> presenta alcuni limiti sulle performance dei thread legate al GIL. Per 
> risolvere

L'implementazione Classic Python (con una sua macchina virtuale 
dedicata) usa appunto un lock globale sull'interprete (GIL) che 
impedisce che puro bytecode Python sia in esecuzione simultanea su 
molteplici thread nello stesso interprete; l'esecuzione simultanea e` 
limitata a codice C che rilasci il GIL (lo fanno ad esempio le librerie 
standard Python per tutte le operazioni bloccanti di I/O, e le tipiche 
estensioni a pesante impegno di CPU come, ad esempio, quelle per il 
calcolo numerico -- ma non tutte [ad esempio non mi sono mai 
preoccupato di rilasciare il GIL nell'estensione gmpy]).  Questo non 
"presenta limiti sulle performance dei thread" su tipici elaboratori 
che dispongono di una singola CPU (anzi, riducendo le necessita` di 
locking, puo` in piccola misura migliorare le performance), ma 
impedisce ad un singolo processo multithreading, con un programma 
scritto interamente in puro Python senza sostanziali componenti I/O 
bound, senza sostanziale uso di estensioni che rilasciano il GIL, ed 
eseguito in Classic Python, di occupare pienamente tutte le risorse di 
calcolo di un singolo computer dotato di molteplici CPU 
("multi-processor").  Ad esempio, passando da un computer 
mono-processor (che mi pare nel mondo PC siano ben oltre il 90%) ad uno 
con due processor, il suddetto programma puro Python non puo` far altro 
che riempire interamente una singola CPU, lasciando all'altra solo 
compiti come quello di eseguire il sistema operativo,  tutti gli altri 
processi in simultanea esecuzione, la rete, l'interfaccia utente, e 
cosi` via.

Piu` incerto e` il discorso relativo alle nuove CPU Intel 
"hyperthreading", che hanno un processore solo ma in un certo senso 
permettono di "simularne" due (o almeno "uno e mezzo", che so) con 
teorico e potenziale beneficio per programmi "freely threaded" (ma non 
il suddetto ipotetico caso).

Di certo questo puo` essere un problema se il tuo scopo e` quello di 
usare un singolo computer con tanti processori per eseguire, in 
pratica, solamente un singolo programma alla volta e detto programma 
rientra nella tipologia suindicata (CPU-intensive ma non usa le tipiche 
estensioni Python in C, ecc, ecc).  Non dubito che _almeno_ lo 0.01% 
dei programmatori Python a tempo pieno si trovera` in situazioni simili 
almeno una volta nel corso della sua vita, anche se in pratica di 
solito, quella volta nella vita che mediamente gli capiteranno, 
risolvera` usando estensioni C, o anche semplicemente una macchina 
virtuale diversa (ad esempio, una qualsiasi macchina virtuale Java, 
grazie all'implementazione "Jython" del linguaggio Python, ovvero 
presto dotNet o Mono, grazie alla implementazione "IronPython" dello 
stesso linguaggio Python recentemente intrapresa da Jim Hugunin, a suo 
tempo inventore di Jython).

> questo problema sembra che l'unica soluzione sia il multiprocess, 
> sbaglio? Il

Se il tuo scopo nella vita e` accelerare (nel senso della 
_scalabiltia`_...) al massimo un ipotetico programma Python della 
tipologia suddetta, e` probabile che strutturarlo come multi-processo 
sia furbo -- ma lo stesso varrebbe per un programma in C, in Java, o 
che altro, perche` una architettura multi-processo ti permette di 
accedere a numeri di processori incomparabilmente maggiori nella 
maggior parte dei casi, rispetto ai numeri risibili tipicamente 
disponibili in SMP (e quindi ai thread usati in C o Java, o 
naturalmente Jython, o quelli che rilasciano il GIL anche in Python 
classico).  In una casa media, ad esempio, e` difficile che ci siano 
computer in SMP al di la` dei semplici Powermac G5, che comunque oltre 
i due processori (a 64 bit) non vanno; Intel e AMD fanno spesso pagare 
un premio eccessivo per qui modelli dei loro processori che hanno 
potenzialita` di uso SMP, per non dire del costo esagerato della 
componentistica di supporto rispetto all'eccellente rapporto 
prezzo/prestazione ottenibile coi chipset limitati all'uso 
monoprocessore, per cui mi pare che nessuno fra i principali fornitori 
di computer per consumatori punti sulle architetture SMP con l'unica 
eccezione, appunto, di Apple (che comunque non si spinge molto in la).  
All'altro capo della gamma, se hai a disposizione un SMP da 4-8 
processori dedicabile ai tuoi processi CPU-intensive, e` probabile che 
potresti anche accedere a un cluster (beowulf o successori, su su sino 
al gigantesco cluster/supercomputer della Virginia, che putacaso si 
basa anch'esso su processori IBM G5 e architetture Apple) di decine, o 
centinaia, o perche` no migliaia di processori, magari connessi fra 
loro a velocita` da fare impallidire i bus interni di molte modeste 
architetture SMP... ma, appunto, NON SMP, non sfruttabili da un singolo 
processo multi-thread, solo da un programma strutturato in molteplici 
processi.

Quindi, pur non essendo l'_unica_, l'architettura a molteplici processi 
puo` essere spesso la strada _migliore_ per ottenere scalabilita` 
esagerata, indipendentemente dal linguaggio di programmazione.

> GIL limita effettivamente l'usabilità dei thread? Esistono altre 
> soluzioni?

L'usabilita` no di certo, solo potenzialmente le prestazioni nell'unico 
caso suddetto su macchine SMP.  Certo che esistono altre soluzioni.  Ad 
esempio nella stragrande maggioranza dei casi le prestazioni di tanti 
programmi saranno I-O bound, non CPU-bound, e allora i thread non 
ottimizzerebbero nulla anche senza GIL, la soluzione ottimale e` il 
"multitasking cooperativo", pilotato dagli eventi, che offre ad esempio 
Twisted.

> Quando e dove è conveniente utilizzare i thread in python rispetto al
> multiprocess? Il supporto dei thread in python  è paragonabile al 
> supporto
> offerto da java in termini di performance?

Mi sembra che possa esserci una certa confusione fra linguaggi e 
macchine virtuali.  Se scrivi un programma usando il linguaggio Python 
puoi poi eseguirlo con la macchina virtuale dedicata classic python 
(prestazioni generalmente migliori, ma GIL) o con una macchina virtuale 
Java (niente GIL, magari altri difetti di prestazioni ad esempio 
sull'I/O, dipende dal modello esatto di JVM e da dove gira) -- o presto 
con una macchina virtuale dotNet o Mono, con vantaggi e svantaggi di 
prestazioni in vari ambiti che saranno ovviamente ancora diversi.

Personalmente, quando scrivo un programma MT in Python lo strutturo 
comunque con un pool di thread indipendenti che comunicano fra loro 
rigorosamente via istanze di Queue.  Oltre ad essere di gran lunga il 
modo migliore per scrivere un programma MT dimostrabilmente corretto, 
e` anche un'architettura che offre la massima facilita` di ri-codifica 
come multi-processo (sostituendo le Queue con costrutti equivalenti 
basati su socket o pipe).  Il giorno che qualcuno mi regalera` un 
cluster di qualche centinaiadi Athlon AMD-64 ne saro` certo felice.  
Per ora, devo ammetterlo, possedendo al massimo un Powermac Dual G5, 
non e` che mi serva a molto... anche perche` di solito i miei programmi 
davvero pesanti sono I/O bound, come per il 99.9% dei comuni mortali (i 
loro colli di bottiglia sono il database, la rete, i dischi, ...) 
quindi per averli prestanti non li faccio MT, li faccio event-driven 
(con Twisted, naturalmente!) e le prestazioni sono sorprendenti (il 
giorno che non lo saranno abbastanza, senza riscrivere una riga del mio 
codice, comincero` a giocare a fondo con le possibilta` che Twisted 
offre per reactor specializzati, compresi quelli multi-thread e 
multi-processo, per ottenere, potenzilamente, scalabilita` anche 
superiore con lo stesso, identico codice applicativo).


Alex




More information about the Python mailing list