Le piège des QThread
source link: https://blog.mathieu-leplatre.info/le-piege-des-qthread-fr.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Le piège des QThread
Thu 01 September 2011Article original publié chez Makina Corpus
Il y a de nombreux billets de blogs, posts sur des forums, tutoriaux, pages Wiki et autres, mais au final, à part le fameux "You're doing it wrong", qui peut paraître obscure au premier abord, je n'ai pas trouvé de résumé de l'attrape-nigaud que je vais illustrer ici.
Le piège
Naturellement, quand on veut faire une thread, on a envie d'hériter de l'objet QThread. C'est ce qu'on fait avec le module threading de python (en Java aussi il me semble).
Voici ce qu'on écrit naturellement : Objet, la classe qui file l'ordre et Worker, une classe qui bosse dur en arrière plan. On connecte les signaux et on démarre !
import sys from PyQt4.QtCore import * from PyQt4.QtGui import QApplication class Object(QObject): def emitSignal(self): self.emit(SIGNAL("aSignal()")) class Worker(QThread): def aSlot(self): self.thread().sleep(1) print "Slot is executed in thread : ", self.thread().currentThreadId() if __name__ == "__main__": app = QApplication(sys.argv) print "Main application thread is : ", app.thread().currentThreadId() worker = Worker() obj = Object() QObject.connect(obj, SIGNAL("aSignal()"), worker.aSlot) worker.start() obj.emitSignal() print "Done." app.exec_()
Ici, comme le slot aSlot() est défini dans la classe Worker, qui hérite de QThread, on pense naturellement qu'il va être exécuté en arrière-plan. Que nenni!
Main application thread is : 140068661352224 # (... wait 1 sec ...) Slot is executed in thread : 140068661352224 Done.
La solution
Un secret ? Les QThread ne sont pas des threads. Elles enrobent l'execution d'une thread.
L'appartenance (affinité) d'un objet à une thread détermine le type de connexion utilisé par défaut, et par conséquent le comportement lors de l'execution des slots.
Ce qu'il faut écrire : Worker n'est plus une QThread, on force son affinité dans une thread avec moveToThread().
class Object(QObject): def emitSignal(self): self.emit(SIGNAL("aSignal()")) class Worker(QObject): def aSlot(self): self.thread().sleep(1) print "Slot is executed in thread : ", self.thread().currentThreadId() if __name__ == "__main__": app = QApplication(sys.argv) print "Main application thread is : ", app.thread().currentThreadId() worker = Worker() obj = Object() thread = QThread() worker.moveToThread(thread) QObject.connect(obj, SIGNAL("aSignal()"), worker.aSlot) thread.start() obj.emitSignal() print "Done." app.exec_()
Désormais, l'exécution est bien asynchrone, comme on le souhaitait.
Main application thread is : 139961882056480 Done. # (... wait 1 sec ...) Slot is executed in thread : 139961512900352
Tout simplement ! Si j'avais lu mon article avant, je n'aurais pas perdu autant de temps à lire toutes ces docs ambiguës sur le Net.
Sources:
#qt, #python, #tips - Posted in the Dev category
© Copyright 2020 by Mathieu Leplatre. mnmlist Theme
Content licensed under the Creative Commons attribution-noncommercial-sharealike License.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK