Questo articolo copre le basi del multithreading nel linguaggio di programmazione Python. Proprio come multielaborazione , il multithreading è un modo per ottenere il multitasking. Nel multithreading, il concetto di discussioni si usa. Cerchiamo innanzitutto di comprendere il concetto di filo nell'architettura informatica.
Cos'è un processo in Python?
Nell'informatica, a processi è un'istanza di un programma per computer che viene eseguito. Qualsiasi processo ha 3 componenti di base:
- Un programma eseguibile.
- I dati associati necessari al programma (variabili, spazio di lavoro, buffer, ecc.)
- Il contesto di esecuzione del programma (Stato del processo)
Un'introduzione al threading Python
UN filo è un'entità all'interno di un processo che può essere pianificata per l'esecuzione. Inoltre, è la più piccola unità di elaborazione che può essere eseguita in un sistema operativo (sistema operativo). In parole semplici, un thread è una sequenza di tali istruzioni all'interno di un programma che può essere eseguita indipendentemente da altro codice. Per semplicità, puoi supporre che un thread sia semplicemente un sottoinsieme di un processo! Un thread contiene tutte queste informazioni in a Blocco di controllo del thread (TCB) :
- Identificatore del thread: L'ID univoco (TID) viene assegnato a ogni nuovo thread
- Puntatore dello stack: Punta allo stack del thread nel processo. Lo stack contiene le variabili locali nell'ambito del thread.
- Contatore di programma: un registro che memorizza l'indirizzo dell'istruzione attualmente eseguita da un thread.
- Stato della discussione: può essere in esecuzione, pronto, in attesa, in avvio o terminato.
- Set di registri del thread: registri assegnati al thread per i calcoli.
- Puntatore del processo principale: Un puntatore al blocco di controllo processo (PCB) del processo su cui risiede il thread.
Considera il diagramma seguente per comprendere la relazione tra il processo e il suo thread:

Relazione tra un processo e il suo thread
Possono esistere più thread all'interno di un processo in cui:
- Ogni thread contiene il proprio insieme di registri E variabili locali (memorizzate nello stack) .
- Tutti i thread di un processo condividono variabili globali (memorizzate nell'heap) e il codice del programma .
Considera il diagramma seguente per capire come esistono più thread in memoria:

Esistenza di più thread in memoria
Un'introduzione al threading in Python
Multithreading è definita come la capacità di un processore di eseguire più thread contemporaneamente. In una semplice CPU single-core, ciò si ottiene utilizzando frequenti passaggi tra thread. Questo è chiamato cambio di contesto . Nel cambio di contesto, lo stato di un thread viene salvato e lo stato di un altro thread viene caricato ogni volta che si verifica un'interruzione (dovuta all'I/O o impostata manualmente). Il cambio di contesto avviene così frequentemente che tutti i thread sembrano essere eseguiti parallelamente (questo è chiamato multitasking ).
Considera il diagramma seguente in cui un processo contiene due thread attivi:

Multithreading
Multithreading in Python
In Pitone , IL filettatura Il modulo fornisce un'API molto semplice e intuitiva per generare più thread in un programma. Cerchiamo di comprendere passo dopo passo il codice multithreading.
powershell contro bash
Passo 1: Modulo di importazione
Innanzitutto, importa il modulo di threading.
import threading>
Passo 2: Crea una discussione
Per creare un nuovo thread, creiamo un oggetto del file Filo classe. Prende 'target' e 'args' come parametri. IL bersaglio è la funzione che deve essere eseguita dal thread mentre il args è gli argomenti da passare alla funzione di destinazione.
t1 = threading.Thread(target, args) t2 = threading.Thread(target, args)>
Passaggio 3: Avvia una discussione
Per avviare una discussione, usiamo il file inizio() metodo della classe Thread.
t1.start() t2.start()>
Passaggio 4: Termina l'esecuzione del thread
Una volta avviati i thread, anche il programma corrente (puoi considerarlo come un thread principale) continua a essere eseguito. Per interrompere l'esecuzione del programma corrente fino al completamento di un thread, utilizziamo il file giuntura() metodo.
t1.join() t2.join()>
Di conseguenza, il programma corrente attenderà prima il completamento di t1 poi t2 . Una volta terminate, vengono eseguite le restanti istruzioni del programma corrente.
Esempio:
Consideriamo un semplice esempio utilizzando un modulo di threading.
Questo codice dimostra come utilizzare il modulo threading di Python per calcolare contemporaneamente il quadrato e il cubo di un numero. Due fili, t1> E t2> , vengono creati per eseguire questi calcoli. Vengono avviati e i relativi risultati vengono stampati in parallelo prima che il programma stampi Fatto! quando entrambi i thread sono finiti. Il threading viene utilizzato per ottenere il parallelismo e migliorare le prestazioni del programma quando si affrontano attività ad alta intensità di calcolo.
Python3
import> threading> def> print_cube(num):> >print>(>'Cube: {}'> .>format>(num>*> num>*> num))> def> print_square(num):> >print>(>'Square: {}'> .>format>(num>*> num))> if> __name__>=>=>'__main__'>:> >t1>=> threading.Thread(target>=>print_square, args>=>(>10>,))> >t2>=> threading.Thread(target>=>print_cube, args>=>(>10>,))> >t1.start()> >t2.start()> >t1.join()> >t2.join()> >print>(>'Done!'>)> |
>
>
Produzione:
Square: 100 Cube: 1000 Done!>
Considera il diagramma seguente per una migliore comprensione di come funziona il programma sopra:

Multithreading
Esempio:
In questo esempio utilizziamo os.getpid() funzione per ottenere l'ID del processo corrente. Noi usiamo threading.main_thread() funzione per ottenere l'oggetto del thread principale. In condizioni normali, il thread principale è il thread da cui è stato avviato l'interprete Python. nome L'attributo dell'oggetto thread viene utilizzato per ottenere il nome del thread. Quindi usiamo il threading.current_thread() funzione per ottenere l'oggetto thread corrente.
Considera il programma Python fornito di seguito in cui stampiamo il nome del thread e il processo corrispondente per ciascuna attività.
Questo codice dimostra come utilizzare il modulo threading di Python per eseguire due attività contemporaneamente. Il programma principale avvia due thread, t1> E t2> , ciascuno responsabile dell'esecuzione di un compito specifico. I thread vengono eseguiti in parallelo e il codice fornisce informazioni sull'ID del processo e sui nomi dei thread. ILos>viene utilizzato per accedere all'ID del processo e al file ' threading'> il modulo viene utilizzato per gestire i thread e la loro esecuzione.
Python3
import> threading> import> os> def> task1():> >print>(>'Task 1 assigned to thread: {}'>.>format>(threading.current_thread().name))> >print>(>'ID of process running task 1: {}'>.>format>(os.getpid()))> def> task2():> >print>(>'Task 2 assigned to thread: {}'>.>format>(threading.current_thread().name))> >print>(>'ID of process running task 2: {}'>.>format>(os.getpid()))> if> __name__>=>=> '__main__'>:> >print>(>'ID of process running main program: {}'>.>format>(os.getpid()))> >print>(>'Main thread name: {}'>.>format>(threading.current_thread().name))> >t1>=> threading.Thread(target>=>task1, name>=>'t1'>)> >t2>=> threading.Thread(target>=>task2, name>=>'t2'>)> >t1.start()> >t2.start()> >t1.join()> >t2.join()> |
>
>
Produzione:
ID of process running main program: 1141 Main thread name: MainThread Task 1 assigned to thread: t1 ID of process running task 1: 1141 Task 2 assigned to thread: t2 ID of process running task 2: 1141>
Lo schema riportato di seguito chiarisce il concetto sopra esposto:

Multithreading
Quindi, questa era una breve introduzione al multithreading in Python. Il prossimo articolo di questa serie copre sincronizzazione tra più thread . Multithreading in Python | Set 2 (sincronizzazione)
Pool di thread Python
Un pool di thread è una raccolta di thread creati in anticipo e che possono essere riutilizzati per eseguire più attività. Il modulo concurrent.futures in Python fornisce una classe ThreadPoolExecutor che semplifica la creazione e la gestione di un pool di thread.
In questo esempio definiamo una funzione di lavoro che verrà eseguita in un thread. Creiamo un ThreadPoolExecutor con un massimo di 2 thread di lavoro. Inviamo quindi due attività al pool utilizzando il metodo di invio. Il pool gestisce l'esecuzione delle attività nei relativi thread di lavoro. Usiamo il metodo di spegnimento per attendere il completamento di tutte le attività prima che il thread principale continui.
Il multithreading può aiutarti a rendere i tuoi programmi più efficienti e reattivi. Tuttavia, è importante fare attenzione quando si lavora con i thread per evitare problemi come condizioni di competizione e deadlock.
Questo codice utilizza un pool di thread creato con concurrent.futures.ThreadPoolExecutor> per eseguire due attività di lavoro contemporaneamente. Il thread principale attende che i thread di lavoro finiscano di utilizzare pool.shutdown(wait=True)> . Ciò consente un'efficiente elaborazione parallela delle attività in un ambiente multi-thread.
Python3
import> concurrent.futures> def> worker():> >print>(>'Worker thread running'>)> pool>=> concurrent.futures.ThreadPoolExecutor(max_workers>=>2>)> pool.submit(worker)> pool.submit(worker)> pool.shutdown(wait>=>True>)> print>(>'Main thread continuing to run'>)> |
>
>Produzione
Worker thread running Worker thread running Main thread continuing to run>