gpt4 book ai didi

python - 如果从后台线程调用私有(private)槽,为什么主事件循环会被卡住?

转载 作者:行者123 更新时间:2023-11-28 19:20:20 28 4
gpt4 key购买 nike

我正在使用 python 和 PySide 开发 GUI 应用程序。我需要在单独的线程中运行长时间的背景任务。对于线程,我决定根据“正确”的方法使用 QThread,而不是从 if 进行子类化(参见 http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/)。因此,为了在后台运行我的长任务,我只需将线程的信号“启动”连接到执行长任务的方法。

出于某种原因,我的程序没有按预期运行。我花了几个小时才发现,如果我将插槽名称重命名为“公共(public)”(删除下划线),一切都会按预期开始工作。我想知道私有(private)插槽有什么问题?似乎由于某种原因,主事件循环在私有(private)槽正在进行时不起作用,尽管我可以看到它是在与主线程不同的线程中执行的(请参见下面的程序输出)。

这是一个重现问题的例子:

from PySide.QtCore import QThread, QObject, QCoreApplication, QTimer
import time
import sys

class BackgroundWorker(QObject):
def __init__(self):
QObject.__init__(self)

def __process(self):
self.process()

def process(self):
print 'Background thread:', QThread.currentThread()
for i in xrange(0, 5):
print 'In background thread', i
time.sleep(1)
self.thread.quit()

def start(self):
self.thread = QThread()
self.moveToThread(self.thread)
#self.thread.started.connect(self.process) # <---- Case 1: This works as expected
self.thread.started.connect(self.__process) # <---- Case 2: Main event loop freezes.
self.thread.finished.connect(app.quit)
self.thread.start()

def main_thread():
print 'Main thread:', QThread.currentThread()
for i in xrange(0, 5):
print 'In main thread', i
time.sleep(1)

if __name__ == '__main__':
app = QCoreApplication(sys.argv)
bw = BackgroundWorker()
QTimer.singleShot(0, bw.start)
QTimer.singleShot(100, main_thread)
app.exec_()

在上面的代码中,方法“BackgroundWorker.start”中有两行用于将线程“启动”信号连接到插槽。 “案例 1”线路按预期工作(连接公共(public)插槽),但“案例 2”线路不正常(连接专用插槽)。

案例 1 的程序输出:

Background thread: <PySide.QtCore.QThread object at 0x02161738>
In background thread 0
Main thread: <PySide.QtCore.QThread object at 0x021616E8>
In main thread 0
In background thread 1
In main thread 1
In background thread 2
In main thread 2
In background thread 3
In main thread 3
In background thread 4
In main thread 4

案例 2 的程序输出:

Background thread: <PySide.QtCore.QThread object at 0x021916E8>
In background thread 0
In background thread 1
In background thread 2
In background thread 3
In background thread 4
Main thread: <PySide.QtCore.QThread object at 0x02191788>
In main thread 0
In main thread 1
In main thread 2
In main thread 3
In main thread 4

我怀疑这在某种程度上与 PySide 中的信号/槽实现有关,但我没有设法找到任何错误报告或与我观察到的行为相关的内容。

PySide版本为1.2.2,python版本为2.6.6

最佳答案

当你在 python 中连接一个 QObject 的方法时,它会自动注册到它的元对象作为一个槽。然而,以双下划线开头的方法不会发生这种情况。

你可以在一个简单的例子中看到这一点:

from PySide.QtCore import *

class Test(QObject):

sig = Signal()

def __test(self):
pass

def test(self):
pass

t = Test()
print(t.metaObject().methodCount()) # prints 5
t.sig.connect(t.test)
print(t.metaObject().methodCount()) # prints 6
t.sig.connect(t._Test__test) # name mangling is applied to the __test method
print(t.metaObject().methodCount()) # still prints 6!

这意味着这样的方法被视为一个普通函数,它连接到一个信号,将始终在主事件线程中运行。如果你真的想使用以__开头的方法名,你需要明确地将它装饰成一个slot,那么它应该可以工作:

from PySide.QtCore import QThread, QObject, QCoreApplication, QTimer, Slot
import time
import sys

class BackgroundWorker(QObject):
def __init__(self):
QObject.__init__(self)

@Slot()
def __process(self):
self.process()

...

关于python - 如果从后台线程调用私有(private)槽,为什么主事件循环会被卡住?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26689643/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com