Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Du 22 au 24 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. PyQt5
  3. Le multithreading en PyQt et sujets assimilés
Extrait - PyQt5 Développez vos interfaces graphiques en Python
Extraits du livre
PyQt5 Développez vos interfaces graphiques en Python
4 avis
Revenir à la page d'achat du livre

Le multithreading en PyQt et sujets assimilés

Introduction

Le cœur du présent chapitre aborde la notion de multithreading : schématiquement, on peut considérer que chaque application s’exécutant sur un ordinateur a son propre processus. Le mutlithreading consiste à faire cohabiter plusieurs threads relatifs à cette application, chacun en charge de différentes tâches.

Le multithreading permet également de faire des appels asynchrones au sein de l’application. En effet, il arrive que l’application ait besoin de ressources qui prennent du temps à être rapatriées, par exemple lorsqu’on accède à une source de données dont la réponse n’est pas immédiate. C’est typiquement la situation dans laquelle il est intéressant de faire un appel asynchrone à la ressource au sein d’un thread dédié. Ceci permet de ne pas altérer le reste du fonctionnement de l’application.

Une communication synchrone est une communication qui a besoin de voir l’émetteur et le récepteur impliqués durant toute la durée de la communication. Par exemple, un appel téléphonique est une communication synchrone. En informatique, une telle communication, par exemple une requête synchrone d’obtention d’une ressource, va tout mettre en suspens dans l’application et provoquer un effet...

Utilisation de la classe QTimer

1. Introduction

L’usage d’un timer (chronomètre) peut permettre de décaler l’exécution d’un traitement. Typiquement, il est ainsi possible d’attendre x secondes pour lancer un calcul. Cette pratique peut donner de la fluidité à l’exécution d’une application fortement sollicitée, même si cette méthode atteint rapidement ses limites.

Pour illustrer l’utilisation de cette classe, prenons l’exemple de développement d’un petit afficheur de l’heure courante incluant les secondes.

2. Développement utilisant QTimer

Pour ce faire, nous allons instancier la classe QTimer en passant en paramètre une durée de une seconde. Ainsi, en utilisant l’évènement timeout, on affichera en fin de chaque seconde l’heure courante.

On commence évidemment par déclarer les imports.

import sys 
from PyQt5.QtWidgets import QVBoxLayout, QPushButton,QApplication, 
QLabel, QWidget 
from PyQt5.QtCore import Qtimer, QDateTime 

Tout le code est dans la classe Fenetre qui hérite de QWidget. On commence par l’instancier.

if __name__ == '__main__': 
    app=QApplication(sys.argv) 
    fenetre=Fenetre() 
    fenetre.show() 
    sys.exit(app.exec_()) 

class Fenetre(QWidget): 

Dans la méthode __init__, on définit la structure de notre fenêtre avec notamment le bouton de lancement...

Le multithreading en PyQt

1. Introduction

L’intérêt de l’usage du multithreading est manifeste dès lors que votre application doit conduire des tâches très longues. En effet, si on lance une tâche très longue dans le thread courant de l’application, une recherche par exemple, alors on risque fortement que notre application ne réponde plus. La fenêtre de l’application apparaîtra toute blanche et il sera impossible de cliquer sur l’interface ou de « faire réagir » un widget. En attente du résultat d’une tâche longue, l’application est alors inutilisable.

Le cas d’école fréquemment repris est celui d’une recherche sur le disque qui prend du temps. Par exemple, on recherche la chaîne de caractères « PyQt » dans les noms de tous les fichiers du disque courant.

Pour que l’application reste fonctionnelle, il faut absolument que le thread principal de l’application délègue la recherche de fichiers à un autre thread. Ainsi :

  • on a le thread principal de l’application ;

  • l’utilisateur fait une recherche et clique sur le bouton Rechercher ;

  • sur le clic du bouton Rechercher, on crée un nouveau thread dévolu à la recherche de fichiers ;

  • quand la recherche est terminée, on affiche les résultats et on détruit éventuellement le thread créé.

C’est ce petit exemple que nous allons traiter dans ce chapitre. Mais préalablement, prenons un autre exemple mettant en évidence l’utilisation simple de la classe QThread.

2. Mise en évidence de l’utilisation de QThread

Dans ce premier exemple qui peut être vu comme un cas d’école, nous allons définir un traitement simple. En l’occurrence, il s’agira de lancer une tâche d’attente de quelques millisecondes. Pour cela, on utilisera la méthode sleep du module Python time.

On définit une fenêtre incluant deux boutons :

  • un bouton permettant de lancer le traitement dans le thread principal de la fenêtre,

  • un bouton permettant de lancer le traitement dans un thread dédié, créé à cet effet.

Comme d’habitude, on précise les imports de notre programme.

from...

Pool de threads en PyQt

1. Introduction

Un pool de threads est un ensemble de threads distincts maintenus en attente de l’affectation à une tâche donnée. De fait, le modèle peut être vu ainsi :

  • On a un ensemble de threads en attente de travaux à réaliser.

  • Dès qu’une tâche est à réaliser, on dédie un thread en attente à cette tâche.

Ceci permet de mettre en place un multithreading sensiblement plus efficace que si on créait et interromptait des threads en fonction des besoins (méthode de la section précedente). Ici, les threads sont « prêts ». On économise, de ce fait, la latence induite par les démarrages et arrêts des threads.

Un pool de threads est donc une collection de threads tenue à disposition de la réalisation des tâches à venir.

En PyQt, on utilise la classe Qt nommée QThreadPool dont la documentation est accessible à l’adresse suivante : https://doc.qt.io/qt-5/qthreadpool.html

Voyons un rapide exemple d’utilisation de cette classe PyQt.

2. Petit exemple d’utilisation de QThreadPool

Dans cet exemple, nous allons lancer un petit traitement grâce à un pool de threads préalablement créé. Pour définir le traitement, nous allons hériter de la classe PyQt QRunnable particulièrement...