Dans la plupart des cours d’informatique, le multithreading et la concurrence en Python sont enseignés dans les cours de backend ou même dans une moindre mesure dans les systèmes d’exploitation. Il en résulte que la plupart des diplômés en informatique sont perdus lorsqu’ils essaient d’écrire des programmes simultanés. Cependant, avec l’avènement du Web 2.0, la concurrence et le multithreading ont pris de l’ampleur et la concurrence est maintenant plus importante que jamais. Ce blog se penchera sur le multithreading et la concurrence en Python. Pour comprendre le multithreading, nous devons d’abord comprendre le thread.

Qu’est-ce qu’un fil?

En programmation informatique, les threads sont des processus légers qui garantissent que chaque processeur exécute ses tâches séparément sur le système. Considérez un thread comme un flux d’exécution et chaque thread peut exécuter son propre ordre d’instructions si nous utilisons le processus de multi-threading, nous pouvons faire en sorte que notre programme exécute différentes parties de son programme à des moments différents, ils s’exécutent tous simultanément mais pas vraiment en parallèle. Chaque thread prend un tour pour atteindre la simultanéité, cela est dû à une fonctionnalité appelée GIL (verrouillage global de l’interpréteur) qui signifie qu’un seul thread peut s’exécuter à la fois, mais ils peuvent tous prendre un tour lorsqu’un thread est inactif afin qu’ils s’exécutent simultanément mais pas vraiment en parallèle. Les programmeurs aiment utiliser Python 3 en raison de ses capacités multi-thread – cela permet à plusieurs processeurs de s’exécuter simultanément et d’effectuer des tâches au nom d’un programme.

Le programme et la tâche peuvent être divisés en deux catégories différentes, ils peuvent être

CPU lié : Il s’agit d’un programme ou d’une tâche qui passe la plupart de son temps à attendre des événements internes tels qu’une tâche gourmande en CPU, il est préférable d’utiliser le multi-traitement pour les tâches liées au CPU.

IO-bound : il s’agit d’un programme de tâches qui passe le plus clair de son temps à attendre des événements externes tels que l’attente d’une entrée utilisateur car si vous effectuez des activités telles que le grattage Web pour ce type de tâche, il est préférable d’utiliser le multi-threading car nous peut avoir plusieurs threads exécutés simultanément mais pas vraiment en parallèle.

Comment utiliser le MultiThreading en Python ?

Pour utiliser le multithreading en Python, deux modules principaux sont utilisés pour gérer les threads.

Le module de fil

Le module thread peut être efficace dans le threading de bas niveau, il existe un module qui fait tout ce que fait le module thread et plus encore. Ce module est le nouveau module de threading.

Le module de filetage

Le module Threading est une implémentation de haut niveau de plusieurs threads utilisés en Python ou de la concurrence en Python. Son objectif principal est de permettre aux développeurs de créer, configurer et utiliser plusieurs threads dans le même programme sur un seul ordinateur exécutant l’interpréteur Python.

Liste de quelques-unes des fonctions utiles définies dans le module threading :

  • activeCount() – Renvoie le nombre d’objets thread actifs qui sont utilisés.
  • currentThread() – Renvoie l’objet actuel de la classe Thread.
  • enumerate() – Renvoie les listes de tous les objets Thread actifs.

Liste de certaines des méthodes utiles de la classe Thread définies dans le module de threading :

  • start() – La méthode start démarre un nouveau thread en appelant la méthode run().
  • run() – La méthode run est utilisée pour indiquer l’activité d’un thread et peut être remplacée par une classe qui étend la classe Thread.
  • join() : une méthode de jointure est utilisée pour bloquer l’exécution d’un autre code jusqu’à ce que le thread soit fermé.

Voici un exemple simple pour le module de threading. Cela comptera le nombre de threads qui s’exécutent actuellement en arrière-plan.

#importing the threading and time module
import threading
import time

print(threading.active_count())
print(threading. enumerate())

Sortir

Chaque fois que nous exécutons le programme et que nous avons un thread en cours d’exécution chargé d’exécuter notre programme, nous pouvons voir le nombre actif du thread qui s’exécute en arrière-plan. Dans la deuxième ligne, nous pouvons voir une liste de tous les threads en cours d’exécution et le thread principal est chargé d’exécuter notre programme ici en utilisant le concept de concurrence en Python, nous pouvons avoir plus d’un thread en cours d’exécution simultanément mais pas vraiment en parallèle.

Atteindre le multithreading à l’aide du module de threading Python

Commençons par créer un programme simple que nous pouvons utiliser pour le multithreading.

#importing the threading and time module
import threading
import time

#creating task one
def Task_one():
    time.sleep(3)
    print("Task one completed")

#creating task two
def Task_two():
    time.sleep(4)
    print("Task two completed")

#creating task three
def Task_three():
    time.sleep(5)
    print("Task three completed")

t = time.time() 
#calling all the function in main thread
Task_one()
Task_two()
Task_three()

print(" Active count of the threads :",threading.active_count())
print(" list of running threads :",threading.enumerate())
print(" Time taken to complete :", time.time() - t) 

Sortir

Ce programme prend environ 12 secondes pour s’exécuter car tous les programmes s’exécutent sur un seul thread. Pour cette raison, leurs tâches sont exécutées séquentiellement et non simultanément, de sorte que l’achèvement d’une tâche nécessitera l’achèvement d’une autre avant qu’une autre puisse commencer.

Ajout de fonctions MultiThreading dans le programme à l’aide du module de threading Python

#importing the threading and time module
import threading
import time

#creating task one
def Task_one():
    time.sleep(3)
    print("Task one complete")

#creating task two
def Task_two():
    time.sleep(4)
    print("Task two complete")

#creating task three
def Task_three():
    time.sleep(5)
    print("Task three complete")

#creating new thread for task one
x = threading.Thread(target=Task_one, args=())
x.start()

#creating new thread for task two
y = threading.Thread(target=Task_two, args=())
y.start()

#creating new thread for task three
z = threading.Thread(target=Task_three, args=())
z.start()

# getting total time to run the functions 
t = time.time()

#print the active count using active count function available in the threading module
print(" Active count of the threads :",threading.active_count())
#print the list of all of the threads that are running using the enumerate function
print(" list of running threads:",threading.enumerate()) print(" Time taken to complete:", time.time() - t) 

Sortir:

Il y a maintenant quatre threads en cours d’exécution sur cette tâche et son exécution prend moins de cinq secondes. Comme nous avons un thread dédié à chacune de ces tâches, nous pouvons les exécuter simultanément au lieu d’une seule après la fin de la précédente. Et vous avez peut-être remarqué que la fonction active de comptage et d’énumération est appelée avant que nos trois fonctions aient terminé leurs tâches respectives, c’est parce que le thread principal n’attendra pas que ces fonctions se terminent, il a son propre ensemble d’instructions pour le faire n’est plus en charge de ces fonctions et c’est aussi la raison pour laquelle le temps total pris par les threads est très faible (0.0009970664978027344).

Synchronisation des threads

Dans la synchronisation des threads, nous pouvons avoir un thread appelant, dans ce cas, notre thread principal attend qu’un autre thread se termine avant de pouvoir continuer avec sa propre instruction.

# here we synchronized thread x, y, and z using the join function  
x.join()
y.join()
z.join()

Après avoir ajouté la fonction de jointure dans le code, notre sortie devrait ressembler à ceci

Sortir:

Dans cette sortie, vous pouvez voir comment nos fonctions se sont terminées en premier et le nombre total d’actifs n’est que de 1 car les threads sont synchronisés et cela indique que le temps nécessaire pour terminer la tâche est d’environ cinq secondes.

Conclusion

Le multithreading n’est rien d’autre que la capacité d’un programme à exécuter plusieurs tâches simultanément. En utilisant un module de threading, vous pouvez créer des threads en Python et accéder à des variables partagées à partir de plusieurs threads dans le même processus. J’espère que ce tutoriel vous donnera une compréhension de base de l’utilisation du module Multithreading en Python. Si vous avez des questions/commentaires concernant ce processus. N’hésitez pas à commenter Bon codage !

Voici quelques tutoriels utiles que vous pouvez lire :