« Programmation Python/Threads » : différence entre les versions

Contenu supprimé Contenu ajouté
DannyS712 (discussion | contributions)
m <source> -> <syntaxhighlight> (phab:T237267)
Aucun résumé des modifications
Ligne 20 :
Au cours de l'histoire de l'informatique, plusieurs techniques ont été mises au point pour partager le temps de travail d'un processeur entre différentes tâches, de telle manière que celles-ci paraissent être effectuées en même temps (alors qu'en réalité le processeur s'occupe d'un petit bout de chacune d'elles à tour de rôle). Ces techniques sont implémentées dans le système d'exploitation, et il n'est pas nécessaire de les détailler ici, même s'il est possible d'accéder à chacune d'elles avec Python.
 
Dans les pages suivantes, nous allons apprendre à utiliser celle de ces techniques qui est à la fois la plus facile à mettre en oeuvreœuvre, et la seule qui soit véritablement portable (elle est en effet supportée par tous les grands systèmes d'exploitation) : on l'appelle la technique des processus légers ou threads<ref>Dans un système d'exploitation de type Unix (comme Linux), les différents ''threads'' d'un même programme font partie d'un seul ''processus''. Il est également possible de gérer différents processus à l'aide d'un même script Python (opération ''fork''), mais l'explication de cette technique dépasse largement le cadre de ce cours.</ref>.
 
Dans un programme d'ordinateur, les threads sont des flux d'instructions qui sont menés en parallèle (quasi-simultanément), tout en partageant le même espace de noms global.
Ligne 328 :
</syntaxhighlight>
 
La classe <code>Pupitre()</code> est construite par dérivation de la classe de même nom importée du modunemodule ''canon03''. Elle hérite donc toutes les caractéristiques de celle-ci, mais nous devons surcharger<ref>Rappel : dans une classe dérivée, vous pouvez définir une nouvelle méthode avec le même nom qu'une méthode de la classe parente, afin de modifier sa fonctionnalité dans la classe dérivée. Cela s'appelle surcharger cette méthode</ref> ses méthodes <code>tirer()</code> et <code>orienter()</code> :
 
Dans la version monoposte du logiciel, en effet, chacun des pupitres pouvait commander directement l'objet canon correspondant. Dans cette version réseau, par contre, ce sont les clients qui contrôlent à distance le fonctionnement des canons. Par conséquent, les pupitres qui apparaissent dans la fenêtre du serveur ne peuvent être que de simples répétiteurs des manoeuvresmanœuvres effectuées par les joueurs sur chaque client. Le bouton de tir et le curseur de réglage de la hausse sont donc désactivés, mais les indications fournies obéissent aux injonctions qui leur sont adressées par l'application principale.
 
Cette nouvelle classe <code>Pupitre()</code> sera également utilisée telle quelle dans chaque exemplaire du programme client. Dans la fenêtre de celui-ci comme dans celle du serveur, tous les pupitres seront affichés comme des répétiteurs, mais l'un d'entre eux cependant sera complètement fonctionnel : celui qui correspond au canon du joueur.
Ligne 998 :
Vous devez bien comprendre que pendant l'écoulement de l'intervalle de temps programmé à l'aide de la méthode <code>after()</code>, votre application n'est pas du tout « figée ». Vous pouvez par exemple pendant ce temps : cliquer sur un bouton, redimensionner la fenêtre, effectuer une entrée clavier, etc. Comment cela est-il rendu possible ?
 
Nous avons mentionné déjà à plusieurs reprises le fait que les applications graphiques modernes comportent toujours une sorte de moteur qui « tourne » continuellement en tâche de fond : ce dispositif se met en route lorsque vous activez la méthode <code>mainloop()</code> de votre fenêtre principale. Comme son nom l'indique fort bien, cette méthode met en oeuvreœuvre une boucle répétitive perpétuelle, du même type que les boucles <code>while</code> que vous connaissez bien. De nombreux mécanismes sont intégrés à ce « moteur ». L'un d'entre eux consiste à réceptionner tous les événements qui se produisent, et à les signaler ensuite à l'aide de messages appropriés aux programmes qui en font la demande (voir : Programmes pilotés par des événements<ref>{{todo|page}}</ref>), d'autres contrôlent les actions à effectuer au niveau de l'affichage, etc. Lorsque vous faites appel à la méthode <code>after()</code> d'un widget, vous utilisez en fait un mécanisme de chronométrage qui est intégré lui aussi à <code>mainloop()</code>, et c'est donc ce gestionnaire central qui déclenche l'appel de fonction que vous souhaitez, après un certain intervalle de temps.
 
La technique d'animation utilisant la méthode <code>after()</code> est la seule possible pour une application fonctionnant toute entière sur un seul thread, parce que c'est la boucle <code>mainloop()</code> qui dirige l'ensemble du comportement d'une telle application de manière absolue. C'est notamment elle qui se charge de redessiner tout ou partie de la fenêtre chaque fois que cela s'avère nécessaire. Pour cette raison, vous ne pouvez pas imaginer de construire un moteur d'animation qui redéfinirait les coordonnées d'un objet graphique à l'intérieur d'une simple boucle <code>while</code>, par exemple, parce que pendant tout ce temps l'exécution de <code>mainloop()</code> resterait suspendue, ce qui aurait pour conséquence que pendant tout ce temps aucun objet graphique ne serait redessiné (en particulier celui que vous souhaitez mettre en mouvement !). En fait, toute l'application apparaîtrait figée, aussi longtemps que la boucle while ne serait pas interrompue.
Ligne 1 018 :
=== Exemple concret ===
 
Le petit script reproduit ci-dessous illustre la mise en oeuvreœuvre de cette technique, dans un exemple volontairement minimaliste. Il s'agit d'une petite application graphique dans laquelle une figure se déplace en cercle à l'intérieur d'un canevas. Son « moteur » <code>mainloop()</code> est lancé comme d'habitude sur le thread principal. Le constructeur de l'application instancie un canevas contenant le dessin d'un cercle, un bouton et un objet thread. C'est cet objet thread qui assure l'animation du dessin, mais sans faire appel à la méthode <code>after()</code> d'un widget. Il utilise plutôt une simple boucle <code>while</code> très classique, installée dans sa méthode <code>run()</code>.
 
[[Image:Apprendre à programmer avec Python 71.png|center|capture d'écran de l'application]]