@pyqtSlot() 对嵌套函数有同样的效果吗?
Has `@pyqtSlot()` same effect on a nested function?
1。简介
我在 Python 3.7 中使用 PyQt5
开发多线程应用程序,为此我依赖 QThread
.
现在假设我有一个从 QObject
派生的 class。在那个 class 中,我定义了一个用 @pyqtSlot
:
注释的函数
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import threading
...
class Worker(QObject):
def __init__(self):
super().__init__()
return
@pyqtSlot()
def some_function(self):
...
return
在其他一些代码中,我实例化 Worker()
并将其移动到一个新线程,如下所示:
my_thread = QThread()
my_worker = Worker()
my_worker.moveToThread(my_thread)
my_thread.start()
QTimer.singleShot(100, my_worker.some_function)
return
通常情况下,some_function()
现在应该 运行 在 my_thread
中。那是因为:
- 我已将
Worker()
对象推送到 my_thread
。
- 当命令
my_thread
开始时,我实际上在该线程中生成了一个new Qt event-loop。 my_worker
对象 存在于此事件循环中。它的所有插槽都可以接收一个事件,该事件将在此事件循环中执行。
some_function()
被正确注释为 @pyqtSlot()
。单次定时器连接到这个插槽并触发一个事件。由于 my_thread
中的 Qt 事件循环,插槽有效地执行了 my_thread
. 中的代码
2。我的问题
我的问题是关于嵌套函数(也称为 'inner functions')。考虑一下:
class Worker(QObject):
def __init__(self):
super().__init__()
return
def some_function(self):
...
@pyqtSlot()
def some_inner_function():
...
return
return
如您所见,some_inner_function()
被注释为@pyqtSlot
。 Worker()
-对象所在的线程中的代码也会运行吗?
3。旁注:如何挂钩到内部函数
您可能想知道我如何将某些内容挂接到内部函数。那么,请考虑以下几点:
class Worker(QObject):
def __init__(self):
super().__init__()
return
def some_function(self):
@pyqtSlot()
def some_inner_function():
# Will this code run in `my_thread`?
...
return
# some_function() will run in the main thread if
# it is called directly from the main thread.
QTimer.singleShot(100, some_inner_function)
return
如果您直接从主线程调用 some_function()
,它将(不幸地)在主线程中调用 运行。如果没有正确使用信号槽机制,您将不会切换线程。
some_function()
内的单发定时器挂在 some_inner_function()
上并触发。内部函数是否会在 my_thread
中执行(假设 Worker()
-object 被分配给 my_thread
)?
在Qt中有以下关于what的规则:
如果您直接调用可调用对象,它将在调用它的线程上 运行。
如果间接调用可调用对象(通过 qt 信号,QTimer::singleShot()
或 QMetaObject::invokeMethod()
),它将在其所属的上下文中执行。而上下文指的是QObject。
如果可调用对象不属于上下文,它将在间接调用它的线程中执行。
内部函数不属于上下文,所以无论是直接调用还是间接调用,都会在被调用的线程中执行。
基于以上,我们分析几个案例作为练习来验证前面的规则:
示例 1
from PyQt5 import QtCore
import threading
class Worker(QtCore.QObject):
def some_function(self):
def some_inner_function():
print("inner thread", threading.get_ident())
QtCore.QThread.sleep(1)
print("worker thread", threading.get_ident())
some_inner_function()
if __name__ == "__main__":
import sys
app = QtCore.QCoreApplication(sys.argv)
thread = QtCore.QThread()
thread.start()
my_worker = Worker()
my_worker.moveToThread(thread)
my_worker.some_function()
print("main thread", threading.get_ident())
sys.exit(app.exec_())
输出:
worker thread 140678349403776
inner thread 140678349403776
main thread 140678349403776
在这种情况下,规则 1 得到满足,因为所有可调用对象都被直接调用。
示例 2
from PyQt5 import QtCore
import threading
class Worker(QtCore.QObject):
def some_function(self):
@QtCore.pyqtSlot()
def some_inner_function():
print("inner thread", threading.get_ident())
QtCore.QThread.sleep(1)
print("worker thread", threading.get_ident())
QtCore.QTimer.singleShot(0, some_inner_function)
if __name__ == "__main__":
import sys
app = QtCore.QCoreApplication(sys.argv)
thread = QtCore.QThread()
thread.start()
my_worker = Worker()
my_worker.moveToThread(thread)
my_worker.some_function()
print("main thread", threading.get_ident())
sys.exit(app.exec_())
输出:
worker thread 139721158932096
main thread 139721158932096
inner thread 139721158932096
这里有些函数是在主线程中直接调用的,所以它会在那个线程中执行,因为 some_inner_function 被 some_function 调用,所以它也会在那个线程中执行.
示例 3:
from PyQt5 import QtCore
import threading
class Worker(QtCore.QObject):
def some_function(self):
@QtCore.pyqtSlot()
def some_inner_function():
print("inner thread", threading.get_ident())
QtCore.QThread.sleep(1)
print("worker thread", threading.get_ident())
QtCore.QTimer.singleShot(0, some_inner_function)
if __name__ == "__main__":
import sys
app = QtCore.QCoreApplication(sys.argv)
thread = QtCore.QThread()
thread.start()
my_worker = Worker()
my_worker.moveToThread(thread)
QtCore.QTimer.singleShot(0, my_worker.some_function)
print("main thread", threading.get_ident())
sys.exit(app.exec_())
输出:
main thread 139934436517504
worker thread 139934378075904
inner thread 139934378075904
在这种情况下,some_function 是间接调用的,属于 Worker 上下文,因此它将在辅助线程上执行,因此 some_inner_function 将在辅助线程上执行。
总而言之,some_inner_function
将 运行 在与 some_function
相同的线程上执行,甚至直接或间接调用它,因为它没有上下文。
1。简介
我在 Python 3.7 中使用 PyQt5
开发多线程应用程序,为此我依赖 QThread
.
现在假设我有一个从 QObject
派生的 class。在那个 class 中,我定义了一个用 @pyqtSlot
:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import threading
...
class Worker(QObject):
def __init__(self):
super().__init__()
return
@pyqtSlot()
def some_function(self):
...
return
在其他一些代码中,我实例化 Worker()
并将其移动到一个新线程,如下所示:
my_thread = QThread()
my_worker = Worker()
my_worker.moveToThread(my_thread)
my_thread.start()
QTimer.singleShot(100, my_worker.some_function)
return
通常情况下,some_function()
现在应该 运行 在 my_thread
中。那是因为:
- 我已将
Worker()
对象推送到my_thread
。 - 当命令
my_thread
开始时,我实际上在该线程中生成了一个new Qt event-loop。my_worker
对象 存在于此事件循环中。它的所有插槽都可以接收一个事件,该事件将在此事件循环中执行。 some_function()
被正确注释为@pyqtSlot()
。单次定时器连接到这个插槽并触发一个事件。由于my_thread
中的 Qt 事件循环,插槽有效地执行了my_thread
. 中的代码
2。我的问题
我的问题是关于嵌套函数(也称为 'inner functions')。考虑一下:
class Worker(QObject):
def __init__(self):
super().__init__()
return
def some_function(self):
...
@pyqtSlot()
def some_inner_function():
...
return
return
如您所见,some_inner_function()
被注释为@pyqtSlot
。 Worker()
-对象所在的线程中的代码也会运行吗?
3。旁注:如何挂钩到内部函数
您可能想知道我如何将某些内容挂接到内部函数。那么,请考虑以下几点:
class Worker(QObject):
def __init__(self):
super().__init__()
return
def some_function(self):
@pyqtSlot()
def some_inner_function():
# Will this code run in `my_thread`?
...
return
# some_function() will run in the main thread if
# it is called directly from the main thread.
QTimer.singleShot(100, some_inner_function)
return
如果您直接从主线程调用 some_function()
,它将(不幸地)在主线程中调用 运行。如果没有正确使用信号槽机制,您将不会切换线程。
some_function()
内的单发定时器挂在 some_inner_function()
上并触发。内部函数是否会在 my_thread
中执行(假设 Worker()
-object 被分配给 my_thread
)?
在Qt中有以下关于what的规则:
如果您直接调用可调用对象,它将在调用它的线程上 运行。
如果间接调用可调用对象(通过 qt 信号,
QTimer::singleShot()
或QMetaObject::invokeMethod()
),它将在其所属的上下文中执行。而上下文指的是QObject。如果可调用对象不属于上下文,它将在间接调用它的线程中执行。
内部函数不属于上下文,所以无论是直接调用还是间接调用,都会在被调用的线程中执行。
基于以上,我们分析几个案例作为练习来验证前面的规则:
示例 1
from PyQt5 import QtCore
import threading
class Worker(QtCore.QObject):
def some_function(self):
def some_inner_function():
print("inner thread", threading.get_ident())
QtCore.QThread.sleep(1)
print("worker thread", threading.get_ident())
some_inner_function()
if __name__ == "__main__":
import sys
app = QtCore.QCoreApplication(sys.argv)
thread = QtCore.QThread()
thread.start()
my_worker = Worker()
my_worker.moveToThread(thread)
my_worker.some_function()
print("main thread", threading.get_ident())
sys.exit(app.exec_())
输出:
worker thread 140678349403776
inner thread 140678349403776
main thread 140678349403776
在这种情况下,规则 1 得到满足,因为所有可调用对象都被直接调用。
示例 2
from PyQt5 import QtCore
import threading
class Worker(QtCore.QObject):
def some_function(self):
@QtCore.pyqtSlot()
def some_inner_function():
print("inner thread", threading.get_ident())
QtCore.QThread.sleep(1)
print("worker thread", threading.get_ident())
QtCore.QTimer.singleShot(0, some_inner_function)
if __name__ == "__main__":
import sys
app = QtCore.QCoreApplication(sys.argv)
thread = QtCore.QThread()
thread.start()
my_worker = Worker()
my_worker.moveToThread(thread)
my_worker.some_function()
print("main thread", threading.get_ident())
sys.exit(app.exec_())
输出:
worker thread 139721158932096
main thread 139721158932096
inner thread 139721158932096
这里有些函数是在主线程中直接调用的,所以它会在那个线程中执行,因为 some_inner_function 被 some_function 调用,所以它也会在那个线程中执行.
示例 3:
from PyQt5 import QtCore
import threading
class Worker(QtCore.QObject):
def some_function(self):
@QtCore.pyqtSlot()
def some_inner_function():
print("inner thread", threading.get_ident())
QtCore.QThread.sleep(1)
print("worker thread", threading.get_ident())
QtCore.QTimer.singleShot(0, some_inner_function)
if __name__ == "__main__":
import sys
app = QtCore.QCoreApplication(sys.argv)
thread = QtCore.QThread()
thread.start()
my_worker = Worker()
my_worker.moveToThread(thread)
QtCore.QTimer.singleShot(0, my_worker.some_function)
print("main thread", threading.get_ident())
sys.exit(app.exec_())
输出:
main thread 139934436517504
worker thread 139934378075904
inner thread 139934378075904
在这种情况下,some_function 是间接调用的,属于 Worker 上下文,因此它将在辅助线程上执行,因此 some_inner_function 将在辅助线程上执行。
总而言之,some_inner_function
将 运行 在与 some_function
相同的线程上执行,甚至直接或间接调用它,因为它没有上下文。