IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Traiter des fichiers en thread

Pour enchainer sur Le QThread de Tyrtamos, cet exemple montre faire traiter des fichiers divers dans des thread.
Le but est de pouvoir sélectionner plusieurs fichiers, chaque fichier sera alors itéré dans un QThread ligne par ligne et chaque ligne traitée par un traitement défini par callback.
Cet exemple est disponible dans les versions PyQt5, PyQt6 et PySide6.
Avatar de fred1599
Expert éminent https://www.developpez.com
Le 08/05/2025 à 15:23
Hello,

Ensemble intéressant, voici quelques remarques qui me semblent empêcher l'optimisation (ce qui semble être recherché sur ce sujet).

  1. Ligne 486 "lig" : len(fic.read_text().split("\n")) - 1. Pour de très gros fichiers, cela peut consommer beaucoup de mémoire et prendre du temps, bloquant potentiellement l'interface utilisateur pendant cette initialisation. Possible de faire ce comptage dans le thread de travail ?
  2. Ligne 530 self.__work.terminate(). Il arrête le thread de manière abrupte, sans lui donner la chance de libérer proprement ses ressources. La méthode stop semble être plus adapté, qu'en penses-tu ?
  3. Ligne 522 QApplication.processEvents(). Je laisserai la boucle d'événements principale de Qt gérer cela.


En résumé, le code est de bonne qualité et bien commenté... Il y a en grande partie le principe SOLID de respecter sauf le O qui est discutable, mais pas gênant car suit une adaptation liée au besoin.
Avatar de fred1599
Expert éminent https://www.developpez.com
Le 08/05/2025 à 16:52
Citation Envoyé par Sve@r
suis en train de discuter en privé avec papajoker qui n'a pas le même avis à propos de mon dictionnaire "ihm" permettant de transmettre les infos entre les objets
ihm est un choix discutable, mais n'indique pas une mauvaise qualité d'un code sur son ensemble...

Citation Envoyé par Sve@r
Faisable mais pas en 2mn
Ce n'est effectivement pas un changement de "2 minutes" car il faut modifier la communication entre le thread et le widget.
Avatar de Sve@r
Expert éminent sénior https://www.developpez.com
Le 08/05/2025 à 17:15
Citation Envoyé par fred1599 Voir le message
Ce n'est effectivement pas un changement de "2 minutes" car il faut modifier la communication entre le thread et le widget.
Ok c'est fait. Et testé sur un fichier de 41M de lignes. Effectivement le comptage est long. Il y a une énorme tempo entre le moment où le thread est créé et le moment où le fichier commence à être lu mais ça ne bloque pas la fenêtre de gestion des fichiers et on peut donc rajouter d'autres fichiers pendant que le premier est toujours en train d'être compté
La version a été uploadée
Avatar de fred1599
Expert éminent https://www.developpez.com
Le 08/05/2025 à 17:29
Citation Envoyé par Sve@r
Effectivement le comptage est long. Il y a une énorme tempo entre le moment où le thread est créé et le moment où le fichier commence à être lu
À mon avis, l'idéal serait de compter les lignes en itérant sur le fichier sans tout charger
Avatar de papajoker
Expert confirmé https://www.developpez.com
Le 08/05/2025 à 17:46
Quelques (autres) remarques
- dommage que le "métier" soit trop imbriqué dans __QtWork, pour moi aucune bonne raison que __QtWork connaisse la nature du travail : ce n'est qu'un widget généraliste.
par exemple :
self.__fic["lig"] pourrait par exemple être envoyé dans le signal sigInfo / "__slotProgress", sigInfo peut envoyer le nombre de lignes du fichier. Voir même sigInfo retourne directement un pourcentage.
self.__fic["nom"] même chose avec __slotStop

- intéressant a faire :
* pouvoir sélectionner plusieurs fichiers .... (Imaginons que j'ai 12 download en parallèle à faire)
* faire une pause lorsque je clic sur stop (sinon le temps de cliquer sur confirmation et c'est déjà fini)
* pourquoi pas ? en option, ajouter le contenu de la ligne au signal "sigInfo" si on ne désire pas utiliser dans certains cas la fonction callback
Avatar de fred1599
Expert éminent https://www.developpez.com
Le 09/05/2025 à 0:05
Citation Envoyé par sve@r
Alors... pour le processEvents() j'avais trouvé ça chez tyrtamos qui m'a beaucoup appris. C'était ici: https://python.jpvweb.com/python/mes...console_python. Il indique que ça force le rafraichissement en temps réel. Cela ne devrait pas gêner de ne pas le mettre.
La plupart du temps, ce n'est pas nécessaire. La boucle d'événements de Qt est très efficace. Il est préférable de le supprimer et de ne le réintroduire que si tu observes concrètement un problème de rafraîchissement visuel que seul processEvents() résout. Même dans ce cas, il faut l'utiliser avec parcimonie.

Citation Envoyé par Sve@r
Je crois que je vais le remplacer par quit() mais mettre l'instruction en commentaire...
Ton thread __cWork exécute une tâche simple dans run() et n'a pas sa propre boucle d'événements Qt, donc quit() n'a pas l'effet escompté ici (il ne va pas interrompre ta boucle for).

Question : Pourquoi avoir commenté wait() ?

Toujours utiliser wait() après avoir demandé l'arrêt coopératif d'un thread, pour s'assurer qu'il a bien terminé avant de continuer et de détruire les objets dont il pourrait dépendre.
Avatar de Sve@r
Expert éminent sénior https://www.developpez.com
Le 09/05/2025 à 0:37
Citation Envoyé par fred1599 Voir le message
Question : Pourquoi avoir commenté wait() ?
Je pensais que puisque je passais par la méthode propre (positionnement du flag ce qui amène le thread a s'arrêter de par la fin de la boucle), cela ne devenait plus nécessaire. Dans ma tête j'associais wait() avec terminate (ou quit) donc puisque pas de quit(), alors pas besoin de wait().

Citation Envoyé par fred1599 Voir le message
Toujours utiliser wait() après avoir demandé l'arrêt coopératif d'un thread, pour s'assurer qu'il a bien terminé avant de continuer et de détruire les objets dont il pourrait dépendre.
Compris (uploadé).

Citation Envoyé par fred1599 Voir le message
La boucle d'événements de Qt est très efficace. Il est préférable de le supprimer et de ne le réintroduire que si tu observes concrètement un problème de rafraîchissement visuel que seul processEvents() résout. Même dans ce cas, il faut l'utiliser avec parcimonie.
Compris (uploadé)
Avatar de fred1599
Expert éminent https://www.developpez.com
Le 09/05/2025 à 1:35
Citation Envoyé par Sve@r
mais je viens d'y penser: puisque wait() est obligatoire, peut-on alors intégrer directement un self.wait() dans la méthode stop()... ?
Oui tu peux, et cela fonctionnera comme attendu parce que la méthode stop() de ton objet thread (self.__work.stop()) est appelée par un autre thread (le thread principal de l'IHM). C'est ce thread appelant qui exécutera le self.__work.wait() et attendra.

Par contre je rendrai cette méthode stop plus robuste,

Code : Sélectionner tout
1
2
3
 
if QThread.currentThread() != self:
    self.wait()
car tu as raison sur ta remarque, un thread ne peut pas attendre que sa propre exécution principale (run()) se termine de cette manière, car il se bloquerait lui-même indéfiniment.
Avatar de Sve@r
Expert éminent sénior https://www.developpez.com
Le 09/05/2025 à 11:18
Citation Envoyé par fred1599 Voir le message
Par contre je rendrai cette méthode stop plus robuste,
Ok, super
De nouveau => uploadé
Developpez.com décline toute responsabilité quant à l'utilisation des différents éléments téléchargés.