Ingresso multithread Python con Esempio: Impara GIL in Python
โก Riepilogo intelligente
Ingresso multithread Python runs several threads inside one process so they share memory and work concurrently. The threading module creates and manages these threads, while the Global Interpreter Lock limits true parallelism, making the technique best for input/output-bound tasks.

Migliori Python programming language allows you to use multiprocessing or multithreading. In this tutorial, you will learn how to write multithreaded applications in Python.
Che cos'รจ un filo?
A thread is a unit of execution in concurrent programming. Multithreading is a technique that allows a CPU to execute many tasks of one process at the same time. These threads can execute individually while sharing their process resources.
Cos'รจ un processo?
A process is basically the program in execution. When you start an application on your computer (like a browser or text editor), the operating system creates a
In cosa consiste il multithreading Python?
Ingresso multithread Python programming is a well-known technique in which multiple threads in a process share their data space with the main thread, which makes information sharing and communication within threads easy and efficient. Threads are lighter than processes. Multiple threads may execute individually while sharing their process resources. The purpose of multithreading is to run multiple tasks and functions at the same time.
Cos'รจ la multielaborazione?
multiprocessing consente di eseguire piรน processi non correlati contemporaneamente. Questi processi non condividono le loro risorse e comunicano tramite IPC.
Python Multithreading e multiprocessing
To understand processes and threads, consider this scenario: An .exe file on your computer is a program. When you open it, the OS loads it into memory, and the CPU executes it. The instance of the program that is now running is called the process.
Every process has two fundamental components:
- Migliori Code
- I dati
Ora, un processo puรฒ contenere una o piรน sottoparti chiamate thread. This depends on the OS architecture. You can think of a thread as a section of the process that can be executed separately by the operating system.
In other words, it is a stream of instructions that can be run independently by the OS. Threads within a single process share the data of that process and are designed to work together to facilitate parallelism.
Perchรฉ utilizzare il multithreading?
Il multithreading consente di suddividere un'applicazione in piรน sotto-attivitร ed eseguirle simultaneamente. Se si utilizza il multithreading correttamente, la velocitร , le prestazioni e il rendering dell'applicazione possono essere tutti migliorati.
Python multithreading
Python supports constructs for both multiprocessing and multithreading. In this tutorial, you will primarily focus on implementing multithreaded applicazioni con Python. There are two main modules that can be used to handle threads in Python:
- Migliori filo modulo, e
- Migliori threading modulo
Tuttavia, in Python, there is also something called a global interpreter lock (GIL). It does not allow for much performance gain and may even ridurre le prestazioni di alcune applicazioni multithread. Imparerai tutto al riguardo nelle prossime sezioni di questo tutorial.
I moduli Thread e Threading
I due moduli che imparerai in questo tutorial sono il modulo filo e modulo di filettatura.
Tuttavia, il modulo thread รจ stato da tempo deprecato. A partire da Python 3, รจ stato designato come obsoleto ed รจ accessibile solo come _thread per la retrocompatibilitร .
Dovresti usare il livello piรน alto threading module for applications that you intend to deploy. The thread module has only been covered here for educational purposes.
Il modulo Discussione
La sintassi per creare un nuovo thread utilizzando questo modulo รจ la seguente:
thread.start_new_thread(function_name, arguments)
Bene, ora hai trattato la teoria di base per iniziare a programmare. Quindi, apri il tuo IDLE oppure un blocco note e digitare quanto segue:
import time import _thread def thread_test(name, wait): i = 0 while i <= 3: time.sleep(wait) print("Running %s\n" %name) i = i + 1 print("%s has finished execution" %name) if __name__ == "__main__": _thread.start_new_thread(thread_test, ("First Thread", 1)) _thread.start_new_thread(thread_test, ("Second Thread", 2)) _thread.start_new_thread(thread_test, ("Third Thread", 3))
Salva il file e premi F5 per eseguire il programma. Se tutto รจ stato fatto correttamente, questo รจ l'output che dovresti vedere:
You will learn more about race conditions and how to handle them in the upcoming sections.
SPIEGAZIONE DEL CODICE
- These statements import the time and thread module, which are used to handle the execution and delaying of the Python thread.
- Qui hai definito una funzione chiamata test_thread, che sarร chiamato dal start_new_thread method. The function runs a while loop for four iterations and prints the name of the thread that called it. Once the iteration is complete, it prints a message saying that the thread has finished execution.
- Questa รจ la sezione principale del tuo programma. Qui, chiami semplicemente il start_new_thread metodo con il thread_test function as an argument. This will create a new thread for the function you pass as an argument and start executing it. Note that you can replace this (thread_test) with any other function that you want to run as a thread.
Il modulo di threading
This module is the high-level implementation of threading in Python and the de facto standard for managing multithreaded applications. It provides a wide range of features when compared to the thread module.
Struttura del modulo Threading
Ecco un elenco di alcune funzioni utili definite in questo modulo:
| Nome della funzione | Descrizione |
|---|---|
| conteggioattivo() | Restituisce il conteggio di Filo objects that are still alive. |
| thread corrente() | Restituisce l'oggetto corrente della classe Thread. |
| enumerare() | Elenca tutti gli oggetti Thread attivi. |
| รจDaemon() | Restituisce vero se il thread รจ un demone. |
| รจ vivo() | Restituisce vero se il thread รจ ancora vivo. |
| Metodi della classe thread | |
| inizio() | Avvia l'attivitร di un thread. Deve essere chiamato solo una volta per ciascun thread perchรฉ genererร un errore di runtime se chiamato piรน volte. |
| correre() | Questo metodo denota l'attivitร di un thread e puรฒ essere sovrascritto da una classe che estende la classe Thread. |
| aderire() | Blocca l'esecuzione di altro codice finchรฉ il thread su cui รจ stato chiamato il metodo join() non viene terminato. |
Storia: la classe Thread
Before you start coding multithreaded programs using the threading module, it is crucial to understand the Thread class. The thread class is the primary class that defines the template and the operations of a thread in Python.
The most common way to create a multithreaded Python application is to declare a class that extends the Thread class and overrides its run() method.
La classe Thread, in sintesi, indica una sequenza di codice che viene eseguita in un file separato filo di controllo.
Quindi, quando scrivi un'app multithread, dovrai fare quanto segue:
- define a class that extends the Thread class
- Sostituisci il __init__ costruttore
- Sostituisci il correre() metodo
Una volta creato un oggetto thread, il file inizio() method can be used to begin the execution of this activity, and the aderire() Il metodo puรฒ essere utilizzato per bloccare tutto il resto del codice fino al termine dell'attivitร corrente.
Now, let us try using the threading module to implement your previous example. Again, fire up your IDLE e digita quanto segue:
import time import threading class threadtester (threading.Thread): def __init__(self, id, name, i): threading.Thread.__init__(self) self.id = id self.name = name self.i = i def run(self): thread_test(self.name, self.i, 5) print ("%s has finished execution " %self.name) def thread_test(name, wait, i): while i: time.sleep(wait) print ("Running %s \n" %name) i = i - 1 if __name__=="__main__": thread1 = threadtester(1, "First Thread", 1) thread2 = threadtester(2, "Second Thread", 2) thread3 = threadtester(3, "Third Thread", 3) thread1.start() thread2.start() thread3.start() thread1.join() thread2.join() thread3.join()
Questo sarร l'output quando esegui il codice sopra:
SPIEGAZIONE DEL CODICE
- This part is the same as our previous example. Here, you import the time and thread module, which are used to handle the execution and delays of the Python thread.
- In questo momento stai creando una classe chiamata threadtester, che eredita o estende il file Filo class of the threading module. This is one of the most common ways of creating threads in Python. However, you should only override the constructor and the correre() metodo nella tua app. Come puoi vedere nell'esempio di codice sopra, il file __init__ il metodo (costruttore) รจ stato sovrascritto. Allo stesso modo, hai anche sovrascritto il file correre() metodo. Contiene il codice che vuoi eseguire all'interno di un thread. In questo esempio, hai chiamato la funzione thread_test().
- This is the thread_test() method, which takes the value of i as an argument, decreases it by 1 at each iteration, and loops through the rest of the code until i becomes 0. In each iteration, it prints the name of the currently executing thread and sleeps for wait seconds (which is also taken as an argument).
- thread1 = threadtester(1, โFirst Threadโ, 1) Qui stiamo creando un thread e passando i tre parametri che abbiamo dichiarato in __init__. Il primo parametro รจ l'id del thread, il secondo parametro รจ il nome del thread e il terzo parametro รจ il contatore, che determina quante volte deve essere eseguito il ciclo while.
- thread2.start() The start method is used to start the execution of a thread. Internally, the start() function calls the run() method of your class.
- thread3.join() Il metodo join() blocca l'esecuzione di altro codice e attende fino al termine del thread su cui รจ stato chiamato.
As you already know, the threads that are in the same process have access to the memory and data of that process. As a result, if more than one thread tries to change or access the data simultaneously, errors may creep in.
In the next section, you will see the different kinds of complications that can show up when threads access data and the critical section without checking for existing access transactions.
Stalli e condizioni di gara
Before learning about deadlocks and race conditions, it will be helpful to understand a few basic definitions related to concurrent programming:
- Sezione critica: It is a fragment of code that accesses or modifies shared variables and must be performed as an atomic transaction.
- Context Switch: It is the process that a CPU follows to store the state of a thread before changing from one task to another so that it can be resumed from the same point later.
Deadlock
Deadlock are the most feared issue that developers face when writing concurrent/multithreaded applications in Python. The best way to understand deadlocks is by using the classic computer science example problem known as the Ristoranti PhiloProblema di Sopher.
Il problema per i filosofi della tavola รจ il seguente:
Five philosophers are seated at a round table with five plates of spaghetti (a type of pasta) and five forks, as shown in the diagram.
Ristoranti PhiloProblema di Sopher
In ogni momento, un filosofo deve stare mangiando o pensando.
Inoltre, un filosofo deve prendere le due forchette adiacenti a lui (cioรจ, la forchetta sinistra e quella destra) prima di poter mangiare gli spaghetti. Il problema dello stallo si verifica quando tutti e cinque i filosofi prendono contemporaneamente la loro forchetta destra.
Poichรฉ ognuno dei filosofi ha una forchetta, aspetteranno tutti che gli altri la appoggino. Di conseguenza, nessuno di loro potrร mangiare gli spaghetti.
Allo stesso modo, in un sistema concorrente, si verifica un deadlock quando diversi thread o processi (filosofi) tentano di acquisire le risorse di sistema condivise (fork) contemporaneamente. Di conseguenza, nessuno dei processi ha la possibilitร di essere eseguito poichรฉ sono in attesa di un'altra risorsa detenuta da un altro processo.
Condizioni di regata
A race condition is an unwanted state of a program that occurs when a system performs two or more operations simultaneously. For example, consider this simple for loop:
i=0; # a global variable for x in range(100): print(i) i+=1;
Se crei n number of threads that run this code at once, you cannot determine the value of i (which is shared by the threads) when the program finishes execution. This is because in a real multithreading environment, the threads can overlap, and the value of i that was retrieved and modified by a thread can change in between when some other thread accesses it.
These are the two main classes of problems that can occur in a multithreaded or distributed Python application. In the next section, you will learn how to overcome this problem by synchronizing threads.
Syncfili cronici
Per gestire condizioni di gara, deadlock e altri problemi basati sui thread, il modulo di threading fornisce bloccare oggetto. L'idea รจ che quando un thread vuole accedere a una risorsa specifica, acquisisce un blocco per quella risorsa. Una volta che un thread blocca una risorsa particolare, nessun altro thread puรฒ accedervi finchรฉ il blocco non viene rilasciato. Di conseguenza, le modifiche alla risorsa saranno atomiche e le condizioni di gara saranno evitate.
Un blocco รจ una primitiva di sincronizzazione di basso livello implementata da _thread module. At any given time, a lock can be in one of two states: bloccato or sbloccato. Supporta due metodi:
- acquire(): When the lock state is unlocked, calling the acquire() method will change the state to locked and return. However, if the state is locked, the call to acquire() is blocked until the release() method is called by some other thread.
- release(): Il metodo release() viene utilizzato per impostare lo stato su sbloccato, ovvero per rilasciare un blocco. Puรฒ essere chiamato da qualsiasi thread, non necessariamente da quello che ha acquisito il lock.
Here is an example of using locks in your apps. Fire up your IDLE e digita quanto segue:
import threading lock = threading.Lock() def first_function(): for i in range(5): lock.acquire() print ('lock acquired') print ('Executing the first funcion') lock.release() def second_function(): for i in range(5): lock.acquire() print ('lock acquired') print ('Executing the second funcion') lock.release() if __name__=="__main__": thread_one = threading.Thread(target=first_function) thread_two = threading.Thread(target=second_function) thread_one.start() thread_two.start() thread_one.join() thread_two.join()
Ora premi F5. Dovresti vedere un output come questo:
SPIEGAZIONE DEL CODICE
- In questo caso stai semplicemente creando una nuova serratura chiamando il file threading.Lock() funzione di fabbrica. Internamente, Lock() restituisce un'istanza della classe Lock concreta piรน efficace gestita dalla piattaforma.
- Nella prima istruzione acquisisci il blocco chiamando il metodo acquire(). Una volta concesso il blocco, si stampa โblocco acquisitoโ alla consolle. Una volta terminata l'esecuzione di tutto il codice che desideri venga eseguito dal thread, rilasci il blocco chiamando il metodo release().
The theory is fine, but how do you know that the lock really worked? If you look at the output, you will see that each of the print statements is printing exactly one line at a time. Recall that, in an earlier example, the outputs from print were haphazard because multiple threads were accessing the print() method at the same time. Here, the print function is called only after the lock is acquired. So, the outputs are displayed one at a time and line by line.
Apart from locks, Python also supports some other mechanisms to handle thread synchronization, as listed below:
- RLocks
- Semaphores
- Condizioni
- Eventi, e
- Barriere
Blocco globale interprete (e come gestirlo)
Prima di entrare nei dettagli di Pythonโs GIL, let us define a few terms that will be useful in understanding the upcoming section:
- CPU-bound code: this refers to any piece of code that will be directly executed by the CPU.
- I/O-bound code: this can be any code that accesses the file system through the OS.
- CPython: รจ il riferimento implementazione of Python e puรฒ essere descritto come l'interprete scritto in C e Python (linguaggio di programmazione).
In cosa consiste GIL Python?
Blocco globale dell'interprete (GIL) in Python is a process lock or a mutex used while dealing with the processes. It makes sure that one thread can access a particular resource at a time, and it also prevents the use of objects and bytecodes at once. This benefits the single-threaded programs with a performance increase. GIL in Python is very simple and easy to implement.
ร possibile utilizzare un blocco per assicurarsi che solo un thread abbia accesso a una particolare risorsa in un dato momento.
Una delle caratteristiche di Python is that it uses a global lock on each interpreter process, which means that every process treats the Python interpreter itself as a resource.
For example, suppose you have written a Python program that uses two threads to perform both CPU and โI/Oโ operations. When you execute this program, this is what happens:
- Migliori Python interpreter creates a new process and spawns the threads.
- Quando il thread-1 inizia a funzionare, acquisirร prima il GIL e lo bloccherร .
- Se il thread-2 vuole essere eseguito adesso, dovrร attendere il rilascio del GIL anche se un altro processore รจ libero.
- Supponiamo ora che il thread-1 sia in attesa di un'operazione di I/O. A questo punto, rilascerร il GIL e il thread-2 lo acquisirร .
- Dopo aver completato le operazioni di I/O, se il thread-1 vuole essere eseguito adesso, dovrร nuovamente attendere che il GIL venga rilasciato dal thread-2.
Due to this, only one thread can access the interpreter at any time, meaning that there will be only one thread executing Python code at a given point in time.
This is alright in a single-core processor because it would be using time slicing (see the first section of this tutorial) to handle the threads. However, in the case of multi-core processors, a CPU-bound function executing on multiple threads will have a considerable impact on the programโs efficiency since it will not actually be using all the available cores at the same time.
Perchรฉ era necessario il GIL?
Il CPython garbage collector uses an efficient memory management technique known as reference counting. Here is how it works: Every object in Python has a reference count, which is increased when it is assigned to a new variable name or added to a container (like tuples, lists, etc.). Likewise, the reference count is decreased when the reference goes out of scope or when the del statement is called. When the reference count of an object reaches 0, it is garbage collected, and the allotted memory is freed.
But the problem is that the reference count variable is prone to race conditions like any other global variable. To solve this problem, the developers of Python decided to use the global interpreter lock. The other option was to add a lock to each object, which would have resulted in deadlocks and increased overhead from acquire() and release() calls.
Therefore, GIL is a significant restriction for multithreaded Python programs running heavy CPU-bound operations (effectively making them single-threaded). If you want to make use of multiple CPU cores in your application, use the multiprocessing modulo invece.








