中断 QThread 睡眠
Interrupting QThread sleep
我想知道如何暂停 QThread 然后在收到信号时恢复。我已经阅读并知道我可以做这样的事情:
def run(self):
...
self.ready=False
while not self.ready:
self.sleep(1)
...
...
@QtCore.Slot()
def set_ready(self):
self.ready = True
但是,我想做的是避免线程中的轮询。我不想将睡眠设置为很短的时间并继续检查。我想去睡觉,直到我从主线程收到继续的信号。
我在我的线程中做的是这样的:
(pseudo code)
with open file:
read a block of data
while data:
sendThread = send the block via UDP
read the next block of data
while not ready or sendThread.isRunning:
sleep(0.1)
在我的主线程中,我设置了一个 QtNetwork.QUdpSocket
来将 readyRead 连接到一个方法来处理传入的数据报并对其进行解码。当它得到我正在等待的响应时,它会向 set_ready
槽发送一个信号,告诉线程发送另一个数据报。我并不总是知道其他系统需要多长时间才能响应,但我可能会有 30 秒左右的超时值。
有没有办法中断线程的休眠?所以我可以这样做:
sleep(30)
if not ready:
Timeout occurred stop processing
else:
Continue processing.
您可以使用 QThreads
的 工作模式 轻松完成此操作。 QThread
文档中有一个 example。确切的代码会有所不同,具体取决于您使用的是 PyQt
还是 PySide
(看起来您使用的是示例中的 PySide
)。
与 PyQt
相比,PySide
的一个显着问题是 they didn't wrap QtCore.Q_ARG
,因此在 PyQt
中,您通常可以使用 QMetaObject.invokeMethod
调用插槽(带参数)在主线程的 Worker
对象上,你不能直接在 PySide
中这样做,必须创建一个 dummy 信号(即.Main.send_signal
) 以连接到 worker 上的插槽,以便您可以从主线程调用它。
import time
import sys
from PySide import QtCore, QtGui
class Worker(QtCore.QObject):
send_signal = QtCore.Signal(str) # using PySide
# QtCore.pyqtSignal(str) ## using PyQt
# @QtCore.pyqtSlot(str)
@QtCore.Slot(str)
def receive_slot(self, data):
# data could be a filepath
# open file
# ... do stuff
# close file
QtCore.QThread.sleep(1) # to simulate doing stuff
self.send_signal.emit(data + ' success')
class Main(QtGui.QWidget):
send_signal = QtCore.Signal(str)
def __init__(self):
super(Main, self).__init__()
self.worker = Worker()
self.thread = QtCore.QThread(self)
self.worker.moveToThread(self.thread)
self.worker.send_signal.connect(self.receive_slot)
self.send_signal.connect(self.worker.receive_slot)
self.thread.start()
self.send_signal.emit('Start')
@QtCore.Slot(str)
def receive_slot(self, data):
print 'Main: {}'.format(data)
self.send_signal.emit('Message {}'.format(time.time()))
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Main()
window.show()
app.exec_()
我想知道如何暂停 QThread 然后在收到信号时恢复。我已经阅读并知道我可以做这样的事情:
def run(self):
...
self.ready=False
while not self.ready:
self.sleep(1)
...
...
@QtCore.Slot()
def set_ready(self):
self.ready = True
但是,我想做的是避免线程中的轮询。我不想将睡眠设置为很短的时间并继续检查。我想去睡觉,直到我从主线程收到继续的信号。
我在我的线程中做的是这样的:
(pseudo code)
with open file:
read a block of data
while data:
sendThread = send the block via UDP
read the next block of data
while not ready or sendThread.isRunning:
sleep(0.1)
在我的主线程中,我设置了一个 QtNetwork.QUdpSocket
来将 readyRead 连接到一个方法来处理传入的数据报并对其进行解码。当它得到我正在等待的响应时,它会向 set_ready
槽发送一个信号,告诉线程发送另一个数据报。我并不总是知道其他系统需要多长时间才能响应,但我可能会有 30 秒左右的超时值。
有没有办法中断线程的休眠?所以我可以这样做:
sleep(30)
if not ready:
Timeout occurred stop processing
else:
Continue processing.
您可以使用 QThreads
的 工作模式 轻松完成此操作。 QThread
文档中有一个 example。确切的代码会有所不同,具体取决于您使用的是 PyQt
还是 PySide
(看起来您使用的是示例中的 PySide
)。
与 PyQt
相比,PySide
的一个显着问题是 they didn't wrap QtCore.Q_ARG
,因此在 PyQt
中,您通常可以使用 QMetaObject.invokeMethod
调用插槽(带参数)在主线程的 Worker
对象上,你不能直接在 PySide
中这样做,必须创建一个 dummy 信号(即.Main.send_signal
) 以连接到 worker 上的插槽,以便您可以从主线程调用它。
import time
import sys
from PySide import QtCore, QtGui
class Worker(QtCore.QObject):
send_signal = QtCore.Signal(str) # using PySide
# QtCore.pyqtSignal(str) ## using PyQt
# @QtCore.pyqtSlot(str)
@QtCore.Slot(str)
def receive_slot(self, data):
# data could be a filepath
# open file
# ... do stuff
# close file
QtCore.QThread.sleep(1) # to simulate doing stuff
self.send_signal.emit(data + ' success')
class Main(QtGui.QWidget):
send_signal = QtCore.Signal(str)
def __init__(self):
super(Main, self).__init__()
self.worker = Worker()
self.thread = QtCore.QThread(self)
self.worker.moveToThread(self.thread)
self.worker.send_signal.connect(self.receive_slot)
self.send_signal.connect(self.worker.receive_slot)
self.thread.start()
self.send_signal.emit('Start')
@QtCore.Slot(str)
def receive_slot(self, data):
print 'Main: {}'.format(data)
self.send_signal.emit('Message {}'.format(time.time()))
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Main()
window.show()
app.exec_()