PyQt5 + Python 3:传递列表,dicts作为跨线程的信号参数
PyQt5 + Python 3: passing lists, dicts as signal arguments across threads
我正在使用 pyqtSignal 将 python 列表作为参数从工作线程发送到主线程。 qt 何时创建作为参数传递的对象的副本。根据:http://www.embeddeduse.com/2013/06/29/copied-or-not-copied-arguments-signals-slots/ qt 应该复制该对象。但是,在下面的示例中,主线程可以更改从另一个线程发送的列表的内容。
import sys
import time
from PyQt5.QtCore import QThread, QObject, pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import QApplication
class ClassProcessing(QObject):
py_sig_send_data = pyqtSignal(list)
def __init__(self):
super().__init__()
# initialize some variables
self.data = [1, 2, 3, 4, 5]
def worker(self):
print(self.data)
self.py_sig_send_data.emit(self.data)
time.sleep(1)
print("modfied data in thread", self.data)
class ClassProcessingThread(QObject):
def __init__(self):
super().__init__()
self.objThread = QThread()
self.objThread_id = 1
self.objThread_finished = False
self.processing = ClassProcessing()
self.processing.moveToThread(self.objThread)
self.objThread.started.connect(self.processing.worker)
self.objThread.start()
class SomeClass(QObject):
def __init__(self):
super().__init__()
@pyqtSlot(list)
def receive_data(self, data):
print("received data", data)
data[1] = 42
print("modified data", data)
def main():
app = QApplication(sys.argv)
processing_thread = ClassProcessingThread()
some_class = SomeClass()
processing_thread.processing.py_sig_send_data.
connect(some_class.receive_data)
sys.exit(app.exec_())
if __name__ == '__main__':
main()
输出:
[1, 2, 3, 4, 5]
received data [1, 2, 3, 4, 5]
modified data [1, 42, 3, 4, 5]
modified data in thread [1, 42, 3, 4, 5]
有人可以向我解释如何以线程安全的方式在 pyqtSignal 中传递列表。谢谢
在使用信号在线程之间传递容器类型时,PyQt 的行为方式与 Qt 不同。
具体来说,没有自动转换 [1] 到等效的 Qt 类型,因此没有隐式复制。不过,PyQt 确实提供了一种机制来 显式 请求此类转换。为此,您可以使用 QVariantList
或 QVariantMap
:
定义自定义信号
py_sig_send_data = pyqtSignal('QVariantList')
不过需要注意的是QVariantMap
只支持字符串键。
不过,总而言之,在通过信号跨线程传递可变 python 类型之前显式复制它们可能更简单、更清晰、更安全。
[1] 或者至少 not any more.
我正在使用 pyqtSignal 将 python 列表作为参数从工作线程发送到主线程。 qt 何时创建作为参数传递的对象的副本。根据:http://www.embeddeduse.com/2013/06/29/copied-or-not-copied-arguments-signals-slots/ qt 应该复制该对象。但是,在下面的示例中,主线程可以更改从另一个线程发送的列表的内容。
import sys
import time
from PyQt5.QtCore import QThread, QObject, pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import QApplication
class ClassProcessing(QObject):
py_sig_send_data = pyqtSignal(list)
def __init__(self):
super().__init__()
# initialize some variables
self.data = [1, 2, 3, 4, 5]
def worker(self):
print(self.data)
self.py_sig_send_data.emit(self.data)
time.sleep(1)
print("modfied data in thread", self.data)
class ClassProcessingThread(QObject):
def __init__(self):
super().__init__()
self.objThread = QThread()
self.objThread_id = 1
self.objThread_finished = False
self.processing = ClassProcessing()
self.processing.moveToThread(self.objThread)
self.objThread.started.connect(self.processing.worker)
self.objThread.start()
class SomeClass(QObject):
def __init__(self):
super().__init__()
@pyqtSlot(list)
def receive_data(self, data):
print("received data", data)
data[1] = 42
print("modified data", data)
def main():
app = QApplication(sys.argv)
processing_thread = ClassProcessingThread()
some_class = SomeClass()
processing_thread.processing.py_sig_send_data.
connect(some_class.receive_data)
sys.exit(app.exec_())
if __name__ == '__main__':
main()
输出:
[1, 2, 3, 4, 5]
received data [1, 2, 3, 4, 5]
modified data [1, 42, 3, 4, 5]
modified data in thread [1, 42, 3, 4, 5]
有人可以向我解释如何以线程安全的方式在 pyqtSignal 中传递列表。谢谢
在使用信号在线程之间传递容器类型时,PyQt 的行为方式与 Qt 不同。
具体来说,没有自动转换 [1] 到等效的 Qt 类型,因此没有隐式复制。不过,PyQt 确实提供了一种机制来 显式 请求此类转换。为此,您可以使用 QVariantList
或 QVariantMap
:
py_sig_send_data = pyqtSignal('QVariantList')
不过需要注意的是QVariantMap
只支持字符串键。
不过,总而言之,在通过信号跨线程传递可变 python 类型之前显式复制它们可能更简单、更清晰、更安全。
[1] 或者至少 not any more.