Python supporta il multithreading? Può accelerare i tempi di esecuzione?


95

Sono un po 'confuso sul fatto che il multithreading funzioni o meno in Python.

So che ci sono state molte domande su questo e ne ho lette molte, ma sono ancora confuso. So per esperienza personale e ho visto altri pubblicare le proprie risposte ed esempi qui su StackOverflow che il multithreading è effettivamente possibile in Python. Allora perché tutti continuano a dire che Python è bloccato dal GIL e che può essere eseguito un solo thread alla volta? Chiaramente funziona. O c'è qualche distinzione che non sto ottenendo qui?

Molti poster / intervistati continuano a menzionare che il threading è limitato perché non fa uso di più core. Ma direi che sono ancora utili perché funzionano contemporaneamente e quindi ottengono il carico di lavoro combinato più velocemente. Voglio dire, perché altrimenti ci sarebbe anche un modulo thread Python?

Aggiornare:

Grazie per tutte le risposte finora. Il modo in cui capisco è che il multithreading verrà eseguito in parallelo solo per alcune attività di I / O, ma può essere eseguito solo uno alla volta per più attività core legate alla CPU.

Non sono del tutto sicuro di cosa significhi per me in termini pratici, quindi fornirò solo un esempio del tipo di attività che vorrei eseguire in multithread. Ad esempio, diciamo che voglio scorrere un elenco molto lungo di stringhe e voglio eseguire alcune operazioni di base sulle stringhe su ogni elemento dell'elenco. Se divido l'elenco, invio ogni sottolista affinché venga elaborata dal mio codice di loop / stringa in un nuovo thread e rimando i risultati in una coda, questi carichi di lavoro verranno eseguiti più o meno allo stesso tempo? Ancora più importante, questo teoricamente accelererà il tempo necessario per eseguire lo script?

Un altro esempio potrebbe essere se posso eseguire il rendering e salvare quattro immagini diverse utilizzando PIL in quattro thread diversi, e fare in modo che questo sia più veloce dell'elaborazione delle immagini una dopo l'altra? Immagino che questo componente della velocità sia ciò su cui mi sto davvero chiedendo piuttosto che qual è la terminologia corretta.

Conosco anche il modulo multiprocessing, ma il mio interesse principale in questo momento è per i carichi di attività medio-piccole (10-30 secondi) e quindi penso che il multithreading sarà più appropriato perché i sottoprocessi possono essere lenti da avviare.


4
Questa è una domanda piuttosto complicata. Penso che la risposta stia in quello che vuoi che i fili facciano. Nella maggior parte dei casi, il GIL impedisce l'esecuzione simultanea di più thread. Tuttavia, ci sono alcuni casi in cui il GIL viene rilasciato (ad esempio la lettura da un file) in modo che possa essere fatto in parallelo. Si noti inoltre che il GIL è un dettaglio dell'implementazione di Cpython (l'implementazione più comune). Nessun'altra implementazione di python (Jython, PyPy, ecc.) Ha un GIL (AFAIK)
mgilson

2
@mgilson PyPy ha un GIL.

2
@delnan - Sembra che tu abbia ragione. Grazie.
mgilson

1
"i sottoprocessi possono essere lenti da avviare" - potresti creare un insieme di attività pronte per essere eseguite. Il sovraccarico può essere limitato all'incirca alla quantità di tempo necessaria per serializzare / deserializzare i dati necessari affinché l'attività inizi a funzionare.
Brian Cain

1
@KarimBahgat, è esattamente quello che intendo.
Brian Cain

Risposte:


132

Il GIL non impedisce la filettatura. Tutto ciò che GIL fa è assicurarsi che un solo thread stia eseguendo codice Python alla volta; il controllo passa ancora da un thread all'altro.

Ciò che il GIL impedisce quindi, è utilizzare più di un core della CPU o CPU separate per eseguire thread in parallelo.

Questo si applica solo al codice Python. Le estensioni C possono rilasciare e rilasciano il GIL per consentire a più thread di codice C e un thread Python di essere eseguiti su più core. Questo si estende all'I / O controllato dal kernel, comeselect() chiamate per le letture e le scritture del socket, rendendo Python la gestione degli eventi di rete ragionevolmente efficiente in una configurazione multi-threaded multi-core.

Ciò che fanno molte distribuzioni di server, è eseguire più di un processo Python, per consentire al sistema operativo di gestire la pianificazione tra i processi per utilizzare al massimo i core della CPU. Puoi anche usare il filemultiprocessing libreria per gestire l'elaborazione parallela tra più processi da una base di codice e un processo genitore, se ciò si adatta ai propri casi d'uso.

Notare che il GIL è applicabile solo all'implementazione di CPython; Jython e IronPython utilizzano un'implementazione di threading diversa (rispettivamente i thread di runtime comune Java VM e .NET nativi).

Per indirizzare direttamente il tuo aggiornamento: qualsiasi attività che cerchi di ottenere un aumento della velocità dall'esecuzione parallela, utilizzando il codice Python puro, non vedrà un aumento della velocità poiché il codice Python filettato è bloccato su un thread in esecuzione alla volta. Se si mescolano estensioni C e I / O, tuttavia (come operazioni PIL o numpy) e qualsiasi codice C può essere eseguito in parallelo con uno thread Python attivo.

Il threading Python è ottimo per creare una GUI reattiva o per gestire più brevi richieste Web in cui l'I / O è il collo di bottiglia più del codice Python. Non è adatto per parallelizzare codice Python ad alta intensità di calcolo, attenersi al multiprocessingmodulo per tali attività o delegare a una libreria esterna dedicata.


Grazie @MartijnPieters, quindi ho una risposta più chiara alla mia domanda se il threading può essere utilizzato per accelerare il codice come un ciclo for, che è "no". Forse tu o qualcuno potresti scrivere una nuova risposta che io possa accettare che fornisca alcuni esempi specifici di moduli / codici / operazioni comuni in cui il threading sarà consentito dal GIL di essere eseguito parallelamente e quindi più velocemente (ad esempio esempi di quegli I / O e rete / operazioni di lettura socket che sono state menzionate e qualsiasi altro caso in cui il multithreading in Python è utile). Forse un bel elenco di usi multithread comuni e alcuni esempi di programmazione, se possibile?
Karim Bahgat

4
No, non credo che una risposta del genere sarebbe molto utile; Ad essere onesti. Non è possibile creare un elenco esaustivo, mai, ma la regola pratica è che qualsiasi I / O (lettura e scrittura di file, socket di rete, pipe) è gestito in C e molte librerie C rilasciano anche il GIL per il loro operazioni, ma spetta alle biblioteche documentarlo per te.
Martijn Pieters

1
Peccato, non ho visto la tua risposta aggiornata fino ad ora, dove hai fornito alcuni bei esempi di utilizzo del thread. Questi includevano (correggimi se sbaglio) la programmazione di rete (ad esempio urllib.urlopen()?), Per chiamare uno script Python dall'interno di una GUI Python e chiamare più operazioni PIL (ad esempio Image.transform()) e numpy (ad esempio numpy.array()) con i thread. E hai fornito alcuni altri esempi nel tuo commento come l'utilizzo di più thread per leggere i file (ad esempio f.read()?). So che un elenco esaustivo non è possibile, volevo solo i tipi di esempi che hai fornito nel tuo aggiornamento. Ad ogni modo,
ho

2
@KarimBahgat: Sì, urllib.urlopen()richiamerei i socket di rete, l'attesa dell'I / O del socket è un'eccellente opportunità per cambiare thread e fare qualcos'altro.
Martijn Pieters

4
Sebbene non sia direttamente rilevante per questo problema, vale la pena notare che a volte il threading non riguarda affatto le prestazioni; potrebbe essere più semplice scrivere il codice come più thread di esecuzione indipendenti. Ad esempio, potresti avere un thread che riproduce musica di sottofondo, uno che serve l'interfaccia utente e uno che si dedica a calcoli che devono essere eseguiti alla fine ma non hanno fretta. Cercare di eseguire la riproduzione in sequenza del buffer audio successivo con il runloop dell'interfaccia utente o di suddividere il calcolo in parti sufficientemente piccole da non interferire con l'interattività, potrebbe essere molto più difficile rispetto all'utilizzo dei thread.
abarnert

4

Sì. :)

Hai il modulo thread di basso livello e il modulo threading di livello superiore . Ma se vuoi semplicemente usare macchine multicore, il modulo multiprocessing è la strada da percorrere.

Citazione dai documenti :

In CPython, a causa del Global Interpreter Lock, solo un thread può eseguire il codice Python contemporaneamente (anche se alcune librerie orientate alle prestazioni potrebbero superare questa limitazione). Se si desidera che la propria applicazione utilizzi meglio le risorse di calcolo delle macchine multi-core, si consiglia di utilizzare il multiprocessing. Tuttavia, il threading è ancora un modello appropriato se si desidera eseguire più attività associate a I / O contemporaneamente.


3

Il threading è consentito in Python, l'unico problema è che il GIL farà in modo che venga eseguito un solo thread alla volta (nessun parallelismo).

Quindi, in pratica, se si desidera eseguire il multi-thread del codice per accelerare il calcolo, non lo accelererà poiché viene eseguito un solo thread alla volta, ma se lo si utilizza per interagire con un database, ad esempio, lo farà.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.