Python 中断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

我想知道如何暂停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 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
函数实际在单独的线程中执行,因此,在线程上创建的任何信号或插槽实际上都在主线程中运行。如果在主线程和工作线程之间来回发送数据,通常最好使用工作线程模型。