Python 中断QThread睡眠
我想知道如何暂停QThread,然后在收到信号时恢复。我读过并且知道我可以做这样的事情:Python 中断QThread睡眠,python,pyqt4,pyside,qthread,Python,Pyqt4,Pyside,Qthread,我想知道如何暂停QThread,然后在收到信号时恢复。我读过并且知道我可以做这样的事情: def run(self): ... self.ready=False while not self.ready: self.sleep(1) ... ... @QtCore.Slot() def set_ready(self): self.ready = True sleep(30) if not ready: Timeout occurr
def run(self):
...
self.ready=False
while not self.ready:
self.sleep(1)
...
...
@QtCore.Slot()
def set_ready(self):
self.ready = True
sleep(30)
if not ready:
Timeout occurred stop processing
else:
Continue processing.
但是,我想做的是避免线程中的轮询。我不想把睡眠时间设置得很短,然后继续检查。我想去睡觉,直到我得到一个信号,从我的主线程继续
我在线程中所做的是:
(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\u ready
插槽发送一个信号,告诉线程发送另一个数据报。我并不总是知道另一个系统需要多长时间才能响应,尽管我可能会有30秒左右的长超时值
有没有办法中断线程的睡眠?所以我可以这样做:
def run(self):
...
self.ready=False
while not self.ready:
self.sleep(1)
...
...
@QtCore.Slot()
def set_ready(self):
self.ready = True
sleep(30)
if not ready:
Timeout occurred stop processing
else:
Continue processing.
使用
QThreads
的辅助模式可以非常轻松地完成这项工作。QThread
文档中有一个。根据您使用的是PyQt
还是PySide
(从您的示例来看,您使用的似乎是PySide
),确切的代码会略有不同
与PyQt
相比,PySide
的一个值得注意的问题是,在PyQt
中,通常可以使用QMetaObject.invokeMethod
从主线程调用Worker
对象上的插槽(带参数),您不能直接在PySide
中执行此操作,必须创建一个虚拟信号(即Main.send\u signal
)来连接到辅助线程上的插槽,以便从主线程调用它
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_()
我对线程编程相当陌生,所以请容忍我。我将文件处理移动到一个单独的线程,因为它挂断了GUI,我想允许用户“取消”该过程。如何使用您的示例打开文件?我通常使用open(filename,'rb')作为二进制文件执行
:
方法。这是可能的,还是我需要在运行QThread
时打开文件,然后在终止时关闭它?我想确保文件正确关闭。我想我会在\uuuu init\uuuu
上打开文件,在插槽中进行处理,然后在线程结束时关闭?你真的想一直打开文件吗?你能把整个文件读入内存,然后关闭它吗?有可能打开文件,做一些操作,然后再关闭它,但是不能在<<代码>中间用上下文暂停操作,也不暂停主线程事件循环(这将冻结GUI)。您可以将整个操作(包括文件打开)移动到工作线程中吗?这样就没有理由在主线程和工作线程之间来回发送数据。问题是文件太大了,我想我可以将整个内容加载到内存中。我试图解决的一个问题是,我正在替换的程序(用Java编写)在用户处理文件之前需要很长时间才能加载文件。所以我试图通过一次加载块来避免这种情况。我应该看看完全加载文件会给我带来多大的时间损失。@busfault更新了答案以显示我的意思。如果希望用户能够取消,可以在名为cancel
的worker上创建一个实例变量,该变量设置为False
,并在worker函数中定期检查。如果主线程想要取消工作线程,只需将其设置为变量self.worker.cancel=True
。当辅助线程检查变量且变量为True
时,它应该停止。您可以继续使用继承的Thread
方法,而不是辅助线程模型,但只需了解QThread
实际上存在于主线程中,只有run
函数实际在单独的线程中执行,因此,在线程上创建的任何信号或插槽实际上都在主线程中运行。如果在主线程和工作线程之间来回发送数据,通常最好使用工作线程模型。