FAQ Python
FAQ PythonConsultez toutes les FAQ
Nombre d'auteurs : 11, nombre de questions : 188, dernière mise à jour : 14 juin 2021
Les 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 =
True
Le 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