FAQ Python

FAQ PythonConsultez toutes les FAQ
Nombre d'auteurs : 11, nombre de questions : 188, dernière mise à jour : 14 juin 2021
Sommaire→ThreadLes Thread en Python s'utilisent très facilement. Pour cela, il suffit de déclarer une instance par le constructeur threading.Thread( group=None, target=None, name=None, args=(), kwargs={}) où :
- group doit rester à None, en attendant que la classe ThreadGroup soit implantée.
- target est la fonction appelée par le Thread.
- name est le nom du Thread.
- args est un tuple d'arguments pour l'invocation de la fonction target
- kwargs est un dictionnaire d'argumens pour l'invocation de la fonction target
il suffit ensuite pour exécuter le Thread d'appliquer la méthode start()
import threading
def affiche(nb, nom = ''):
for i in range(nb): print nom, i
a = threading.Thread(None, affiche, None, (200,), {'nom':'thread a'})
b = threading.Thread(None, affiche, None, (200,), {'nom':'thread b'})
a.start()
b.start()
Nous allons ici simplement nous intéresser aux threads ne présentant pas d'accès concurrent à des ressources. L'objectif
est donc simplement de tuer le thread lancé. Il existe pour cela plusieurs méthodes. Une première est d'appeler simplement la
méthode MonThread._Thread__stop() qui termine l'instruction en cours et tue ensuite le thread.
Une deuxième méthode plus propre est de définir un paramètre Terminated initialisé à False et dand la méthode run
de lancer une boucle infinie testant le booléen Terminated. Enfin, définissez une méthode stop qui met simplement le paramètre
Terminated à True. Vous pouvez ajouter ou non un timer dans la méthode run pour que le thread
ne monopolise pas toutes les ressources CPU. Vous retrouvez un tel exemple avec la classe Affiche. Pour arrêter le thread, on appelle simplement
la méthode stop et une fois la boucle while entièrement parcourue, le thread se termine.
import threading
import time
class Affiche(threading.Thread):
def __init__(self, nom = ''):
threading.Thread.__init__(self)
self.nom = nom
self.Terminated = False
def run(self):
i = 0
while not self.Terminated:
print self.nom, i
i += 1
time.sleep(2.0)
print "le thread "+self.nom +" s'est termine proprement"
def stop(self):
self.Terminated = TrueLe problème de la méthode précédente est donc le fait qu'il peut y avoir un laps de temps important entre le moment de la demande de l'arrêt du thread et celui où le thread est réèllement terminé dû à la durée du timer. En utilisant la classe Event, on peut ainsi accélérer l'arrêt du thread car la méthode monevent.wait(timeout) bloque le thread pendant la durée timeout où jusqu'au moment où la méthode monevent.set() est appelée. La classe Affiche2 présente un exemple sur ce principe.
class Affiche2(threading.Thread):
def __init__(self, nom = ''):
threading.Thread.__init__(self)
self.nom = nom
self._stopevent = threading.Event( )
def run(self):
i = 0
while not self._stopevent.isSet():
print self.nom, i
i += 1
self._stopevent.wait(2.0)
print "le thread "+self.nom +" s'est termine proprement"
def stop(self):
self._stopevent.set( )
a = Affiche('Thread A')
b = Affiche('Thread B')
c = Affiche2('Thread C')
a.start()
b.start()
c.start()
time.sleep(6.5)
a._Thread__stop()
b.stop()
c.stop()A ma connaissance, il n'existe pas d'objet intrinsèque permettant de gérer un timer afin d'exécuter périodiquement un bout de code. Il est cependant possible avec la classe threading.Timer( interval, function, args=[], kwargs={}) de simuler ce comportement. Vous pouvez alors créer une fonction qui lancera un objet threading.Timer sur elle-même, ce qui aura pour effet de répéter périodiquement cette fonction. A la création de l'objet, vous devez fournir un flottant interval indiquant le temps d'attente (après le lancement de la méthode start()) avant l'exécution de la fonction function lancée avec les arguments args et kwargs.
import threading
import time
def MyTimer(tempo = 1.0):
threading.Timer(tempo, MyTimer, [tempo]).start()
## verification de la proprete du timer
print time.clock()
## Reste du traitement
MyTimer(2.0)L'exemple précédent très simple ne permet pas de stopper et de relancer le Timer à votre guise.
Voici un exemple d'une classe gérant un Timer avec possibilité de l'arrêter et de le relancer. Ce Timer prend en paramètre
la période du Timer (tempo), la fonction à appeler (target) et les arguments à passer à la fonction (une liste
args et un dictionnaire kwargs). Vous pouvez alors lancer la fonction par la méthode start() et l'arrêter par la méthode stop()
# -*- coding: cp1252 -*-
import threading
import time
class MyTimer:
def __init__(self, tempo, target, args= [], kwargs={}):
self._target = target
self._args = args
self._kwargs = kwargs
self._tempo = tempo
def _run(self):
self._timer = threading.Timer(self._tempo, self._run)
self._timer.start()
self._target(*self._args, **self._kwargs)
def start(self):
self._timer = threading.Timer(self._tempo, self._run)
self._timer.start()
def stop(self):
self._timer.cancel()
def affiche(unstr):
print unstr, time.clock()
a = MyTimer(1.0, affiche, ["MyTimer"])
a.start()
time.sleep(5.5)
print u"Timer arrêté"
a.stop()
time.sleep(2.0)
print u"Timer relancé"
a.start()Il existe d'autres implémentations de Timer, par exemple la bibliothèque wxPython fournit un objet wx.Timer



