因此,在发出跨线程信号时,使用threading.Thread和QThread并没有真正的区别,只要Python和Qt都使用相同的底层本机线程库即可.这表明在PyQt应用程序中首选使用QThread的一个可能原因是 portability ,因为这样就不会混合使用不兼容的线程实现.但是,考虑到Python和Qt都是故意设计为跨平台的,因此该问题在实践中极不可能出现.关于slot将在哪个线程中执行的问题-对于Python和Qt,它将在 main 线程中执行.相比之下,run方法将在 worker 线程中执行.在Qt应用程序中执行多线程时,这是一个非常重要的考虑因素,因为在主线程之外执行GUI操作并不安全.使用信号可以使您安全地在工作线程和gui之间进行通信,因为连接到从工作线程发出的信号的插槽将在主线程中调用,并允许您在必要时在那里更新gui.下面是一个简单的脚本,显示了每个方法在哪个线程中调用:import sys, time, threadingfrom PyQt5 import QtCore, QtWidgetsdef thread_info(msg): print(msg, int(QtCore.QThread.currentThreadId()), threading.current_thread().name)class PyThreadObject(QtCore.QObject): sig = QtCore.pyqtSignal() def start(self): self._thread = threading.Thread(target=self.run) self._thread.start() def run(self): time.sleep(1) thread_info('py:run') self.sig.emit()class QtThreadObject(QtCore.QThread): sig = QtCore.pyqtSignal() def run(self): time.sleep(1) thread_info('qt:run') self.sig.emit()class Window(QtWidgets.QWidget): def __init__(self): super(Window, self).__init__() self.pyobj = PyThreadObject() self.pyobj.sig.connect(self.pyslot) self.pyobj.start() self.qtobj = QtThreadObject() self.qtobj.sig.connect(self.qtslot) self.qtobj.start() def pyslot(self): thread_info('py:slot') def qtslot(self): thread_info('qt:slot')if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) window = Window() window.setGeometry(600, 100, 300, 200) window.show() thread_info('main') sys.exit(app.exec_())输出: main 140300376593728 MainThreadpy:run 140299947104000 Thread-1py:slot 140300376593728 MainThreadqt:run 140299871450880 Dummy-2qt:slot 140300376593728 MainThread I would like to know what are the consequences of emitting a signal from a regular python thread within a QObject, compared with a QThread.See the following class:class MyObject(QtCore.QObject): def __init__(self): super().__init__() sig = pyqtSignal() def start(self): self._thread = Thread(target=self.run) self._thread.start() def run(self): self.sig.emit() # Do somethingNow, assuming that in the GUI thread, I have:def __init__(self): self.obj = MyObject() self.obj.sig.connect(self.slot) self.obj.start()def slot(self): # Do somethingthe slot is indeed executed when the signal is emitted. However, I would like to know which thread will the slot method be executed in? Would it be any different if I used a QThread instead of a python thread in MyObject?I am using PyQt5 and Python 3. 解决方案 By default, Qt automatically queues signals when they are emitted across threads. To do this, it serializes the signal parameters and then posts an event to the event-queue of the receiving thread, where any connected slots will eventually be executed. Signals emitted in this way are therefore guaranteed to be thread-safe.With regard to external threads, the Qt docs state the following:In general, if the docs state that a Qt API is thread-safe, that guarantee applies to all threads that were created using the same native library - not just the ones that were created by Qt itself. This means it is also safe to explicitly post events to other threads using such thread-safe APIs as postEvent() and invoke().There is therefore no real difference between using threading.Thread and QThread when it comes to emitting cross-thread signals, so long as both Python and Qt use the same underlying native threading library. This suggests that one possible reason to prefer using QThread in a PyQt application is portability, since there will then be no danger of mixing incompatible threading implementations. However, it is highly unlikely that this issue will ever arise in practice, given that both Python and Qt are deliberately designed to be cross-platform.As to the question of which thread the slot will be executed in - for both Python and Qt, it will be in the main thread. By contrast, the run method will be executed in the worker thread. This is a very important consideration when doing multi-threading in a Qt application, because it is not safe to perform gui operations outside the main thread. Using signals allows you to safely communicate between the worker thread and the gui, because the slot connected to the signal emitted from the worker will be called in the main thread, allowing you to update the gui there if necessary.Below is a simple script that shows which thread each method is called in:import sys, time, threadingfrom PyQt5 import QtCore, QtWidgetsdef thread_info(msg): print(msg, int(QtCore.QThread.currentThreadId()), threading.current_thread().name)class PyThreadObject(QtCore.QObject): sig = QtCore.pyqtSignal() def start(self): self._thread = threading.Thread(target=self.run) self._thread.start() def run(self): time.sleep(1) thread_info('py:run') self.sig.emit()class QtThreadObject(QtCore.QThread): sig = QtCore.pyqtSignal() def run(self): time.sleep(1) thread_info('qt:run') self.sig.emit()class Window(QtWidgets.QWidget): def __init__(self): super(Window, self).__init__() self.pyobj = PyThreadObject() self.pyobj.sig.connect(self.pyslot) self.pyobj.start() self.qtobj = QtThreadObject() self.qtobj.sig.connect(self.qtslot) self.qtobj.start() def pyslot(self): thread_info('py:slot') def qtslot(self): thread_info('qt:slot')if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) window = Window() window.setGeometry(600, 100, 300, 200) window.show() thread_info('main') sys.exit(app.exec_())Output:main 140300376593728 MainThreadpy:run 140299947104000 Thread-1py:slot 140300376593728 MainThreadqt:run 140299871450880 Dummy-2qt:slot 140300376593728 MainThread 这篇关于使用QObject从Python线程发出信号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
07-05 06:51