Python : Programmation Asynchrone

De Justine's wiki
Version datée du 25 novembre 2018 à 21:01 par Justine (discussion | contributions) (Page créée avec «   Les informations sont issues de [http://apprendre-python.com/page-programmation-asynchrone-python-thread-threading http://apprendre-python.com/page-programmation-a... »)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à la navigation Aller à la recherche

  Les informations sont issues de http://apprendre-python.com/page-programmation-asynchrone-python-thread-threading et de https://openclassrooms.com/fr/courses/235344-apprenez-a-programmer-en-python/2235545-la-programmation-parallele-avec-threading La programmation asynchrone permet de lancer plusieurs processus en simultané, en lançant plusieurs instructions en même temps. Cela peut permettre de gagner du temps.

Cela passe par le module threading.

Je vais utiliser un script plus simple que celui du cours pour présenter ce concept. On va partir de ce script qui affiche les chiffres de 0 à 9, deux fois.

import threading
import sys

def boucle1():
    for i in range(10):
        sys.stdout.write(str(i) + "\n")

def boucle2():
    for i in range(10):
       sys.stdout.write(str(i) + "\n")

boucle1()     #Les deux fonctions sont lancées l'une après l'autre
boucle2()

 

Sans surprise, ce script émet les deux séries de nombres sur la sortie standard, dans l'ordre. On aurait pu passer par des prints ici, mais le fait d'utiliser la sortie standard se justifie lorsque l'on passe par du threading : les prints ne marchent plus, [je suppose] parce que les threads sont lancés dans un autre terminal?

La version avec thread donne :

import threading
import sys

def boucle1():
    for i in range(10):
        sys.stdout.write(str(i) + "\n")

def boucle2():
    for i in range(10):
       sys.stdout.write(str(i) + "\n")

threading1 = threading.Thread(target=boucle1, args=()) #Les threads sont des objets 
threading2 = threading.Thread(target=boucle2, args=())

threading1.start()  #...lancés par leur fonction start
threading2.start()

La sortie est intéressante:

justine@Justine-pc:~$ python3 testthread.py
0
1
0
2
1
3
4
2
3
5
6
7
8
9
4
5
6
7
8
9

Les nombres ne sortent plus dans l'ordre ! Les deux threads sont lancés quasiment en même temps, et émettent en même temps.

D'autres essais, fait en modifiant le script pour qu'il affiche la boucle dont est issue le string affiché, montrent que parfois les sorties sont dans l'ordre, et parfois non. Il peut alors être important de tenir compte du fait que les deux threads ne sont pas forcément synchronisés. C'est là l'utilité des RLocks, qui permettent de verrouiller un thread ou une partie d'un thread : la partie verrouillée d'un thread ne pourra s'exécuter qu'un seul thread à la fois.

Par exemple :

import threading
import sys
from threading import RLock

verrou = RLock()

def boucle1():
    with verrou:
        for i in range(10):
            sys.stdout.write("Boucle1" + "\n")

def boucle2():
    with verrou:
        for i in range(10):
            sys.stdout.write("Boucle2" + "\n")

#boucle1()     #Les deux fonctions sont lancées l'une après l'autre
#boucle2()

threading1 = threading.Thread(target=boucle1, args=())
threading2 = threading.Thread(target=boucle2, args=())

threading1.start()
threading2.start()

Ici, la sortie sera toujours boucle1, puis boucle2. Ici, on crée un objet RLock nommé verrou. Ensuite, on passe cet objet à chacune de nos fonction via un context manager (un cours là-dessus devrait suivre). Chaque fonction ne pourra s'exécuter que si elle peut verrouiller le lock, ce qui n'est possible qu'une seule fonction à la fois.