gpt4 book ai didi

python - 正确使用 QThread.currentThreadId()

转载 作者:太空狗 更新时间:2023-10-29 22:26:24 24 4
gpt4 key购买 nike

我认为确定当前运行函数的 QThread 的 ID 是 QThread.currentThreadId()。但是我发现这没有给出预期的结果(在 PyQt5 和 python 3 中;但我没有理由相信它会与 pyqt4/py 2 不同,因此通用标签)。线程 ID 以我无法解释的方式变化,表明我实际上无法使用它,其中 QThread 实例 ID 可预测地变化,表明我应该使用它来识别当前正在运行的线程。为了测试,我创建了这个:

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import pyqtSignal
import time
import sys

def logthread(caller):
print('%-25s: %s, %s' % (caller, QtCore.QThread.currentThread(), QtCore.QThread.currentThreadId()))


class Worker(QtCore.QObject):
done = pyqtSignal()

def __init__(self, parent=None):
logthread('worker.__init__')
super().__init__(parent)

def run(self, m=10):
logthread('worker.run')
for x in range(m):
y = x + 2
time.sleep(0.001)
logthread('worker.run finished')

self.done.emit()


class MainWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
logthread('mainwin.__init__')
super().__init__(parent)

self.worker = Worker()
self.workerThread = None

self.btn = QtWidgets.QPushButton('Start worker in thread')
self.btn2 = QtWidgets.QPushButton('Run worker here')
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.btn)
layout.addWidget(self.btn2)

self.run()

def run(self):
logthread('mainwin.run')

self.workerThread = QtCore.QThread()
self.worker.moveToThread(self.workerThread)
self.worker.done.connect(self.workerDone)
self.btn.clicked.connect(self.worker.run)
self.btn2.clicked.connect(self.runWorkerHere)

self.workerThread.start()
self.show()

def workerDone(self):
logthread('mainwin.workerDone')

def runWorkerHere(self):
logthread('mainwin.runWorkerHere')
self.worker.run()


if __name__ == '__main__':
app = QtWidgets.QApplication([])
logthread('main')

window = MainWindow()
sys.exit(app.exec_())

当你运行它时,打印的前 4 行发生在事件循环进入之前,表明 QThread.currentThread() Python id 在几个位置是不同的,但是 QThread .currentThreadId() 是一样的:

main                     : <PyQt5.QtCore.QThread object at 0x01ABDD00>, <sip.voidptr object at 0x01A4ABC0>
mainwin.__init__ : <PyQt5.QtCore.QThread object at 0x01ABDD50>, <sip.voidptr object at 0x01A4ABC0>
worker.__init__ : <PyQt5.QtCore.QThread object at 0x01ABDDA0>, <sip.voidptr object at 0x01A4ABC0>
mainwin.run : <PyQt5.QtCore.QThread object at 0x01ABDE90>, <sip.voidptr object at 0x01A4ABC0>

我希望所有 QThread Python id 都相同,但好吧,也许 QThread 的几个实例包装了相同的 C++ 线程指针。

现在单击“在此处运行工作程序”按钮:这只是直接从 GUI 线程调用 worker.run 方法,因此该方法应表明它正在该线程中运行。这将打印这四行:

mainwin.runWorkerHere    : <PyQt5.QtCore.QThread object at 0x01ABDEE0>, <sip.voidptr object at 0x01A4ABC0>
worker.run : <PyQt5.QtCore.QThread object at 0x01ABDEE0>, <sip.voidptr object at 0x01A4ABC0>
worker.run finished : <PyQt5.QtCore.QThread object at 0x01ABDEE0>, <sip.voidptr object at 0x01A4ACC8>
mainwin.workerDone : <PyQt5.QtCore.QThread object at 0x01ABDEE0>, <sip.voidptr object at 0x01A4ABC0>

确实这次 QThread 实例 ID 在所有行上都是相同的,很高兴看到。但是第 3 行的线程 ID 不同,该行作为 worker.run 中信号的结果由插槽打印,但信号是在同一个线程中生成的!此外,这意味着同一个 QThread 对象可以有多个底层线程 ID。

现在点击“Start Worker”。这会调用 worker.run 但在工作线程中。打印的 3 行是:

worker.run               : <PyQt5.QtCore.QThread object at 0x01ABDE90>, <sip.voidptr object at 0x01A4ABC0>
worker.run finished : <PyQt5.QtCore.QThread object at 0x01ABDE90>, <sip.voidptr object at 0x01A4ACC8>
mainwin.workerDone : <PyQt5.QtCore.QThread object at 0x01ABDEE0>, <sip.voidptr object at 0x01A4ACC8>

QThread 实例 ID 在 worker.run 中(前两行)与在插槽中不同,这是有道理的。线程 ID (sip.voidptr) 的变化方式对我来说毫无意义:我希望第 2 行显示线程 id 0x01A4ABC0,与第一行相同,而不是与第 3 行相同线(插槽)。

有趣的是,如果你用QtWidgets.QApplication.instance().thread()替换logthread格式输出的线程id,你会发现QThread 实例 ID 始终 与应用程序 QThread 实例 ID 相同,除非 worker.run` 在单独的线程中运行。甚至在进入应用程序事件循环之前(换句话说,应用程序线程 ID 仅在事件循环开始后才变为常量)。

如果我测试的是正确的,以上表明一旦 QApplication 事件循环开始,QThread 实例 ID 具有一致且可预测的值,但是线程 ID (currentThreadId()) 没有。因此,无论何时我想测试正在运行的函数的线程位置,我都应该使用 QThread.currentThread() 并可能与 app.thread() 进行比较,但我应该避免 currentThreadId()。有人看到我测试这个的方式和结论有什么问题吗?如果没有问题,考虑到 currentThreadId() 的文档,这有什么意义?如果我犯了错误,我做错了什么?

最佳答案

您的问题主要源于您没有将返回的 sip.voidptr 转换为整数这一事实。如果你改为打印 int(QThread.currentThreadId()) 你会得到有意义的数字。简而言之,您正在查看的是存储 threadId 的内存位置的地址,这显然取决于应用程序当前的内存使用情况。不过,这些内存地址的内容总是一致的。

您可能还想知道 Python 线程模块为您提供了相同的一致信息(参见下面的示例)。

最后一件事,我觉得你的应用程序不是线程安全的,因为你将你的 self.worker 对象移动到 QThread,然后当你单击“运行”时直接从主线程调用方法 worker 在这里”。在下面的示例中,为了安全起见,我在这种情况下实例化了一个新的工作对象。

此外,请原谅将您的示例转换为 PyQt4 和 Python 2.7!

from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import pyqtSignal
import time
import sys
import threading

def logthread(caller):
print('%-25s: %s, %s,' % (caller, QtCore.QThread.currentThread(), int(QtCore.QThread.currentThreadId())))
print('%-25s: %s, %s,' % (caller, threading.current_thread().name, threading.current_thread().ident))


class Worker(QtCore.QObject):
done = pyqtSignal()

def __init__(self, parent=None):
logthread('worker.__init__')
super(Worker, self).__init__(parent)

def run(self, m=10):
logthread('worker.run')
for x in range(m):
y = x + 2
time.sleep(0.001)
logthread('worker.run finished')

self.done.emit()


class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
logthread('mainwin.__init__')
super(MainWindow, self).__init__(parent)

self.worker = Worker()
self.workerThread = None

self.btn = QtGui.QPushButton('Start worker in thread')
self.btn2 = QtGui.QPushButton('Run worker here')
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.btn)
layout.addWidget(self.btn2)

self.run()

def run(self):
logthread('mainwin.run')

self.workerThread = QtCore.QThread()
self.worker.moveToThread(self.workerThread)
self.worker.done.connect(self.workerDone)
self.btn.clicked.connect(self.worker.run)
self.btn2.clicked.connect(self.runWorkerHere)

self.workerThread.start()
self.show()

def workerDone(self):
logthread('mainwin.workerDone')

def runWorkerHere(self):
logthread('mainwin.runWorkerHere')
worker = Worker()
worker.done.connect(self.workerDone)
worker.run()
# self.worker.run()


if __name__ == '__main__':
app = QtGui.QApplication([])
logthread('main')

window = MainWindow()
sys.exit(app.exec_())

关于python - 正确使用 QThread.currentThreadId(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23452218/

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