2016-05-09 3 views
2

Я хотел бы знать, как приостановить QThread, а затем возобновить, когда я получу сигнал. Я прочел и знаю, что я могу сделать что-то вроде этого:Прерывание QThread sleep

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. 

ответ

2

Вы можете сделать это довольно легко, используя шаблон работник использования QThreads. В документации QThread есть example. Точный код будет немного отличаться в зависимости от того, используете ли вы PyQt или PySide (похоже, вы используете в своем примере PySide).

Заметная проблема с PySide по сравнению с PyQt, что they didn't wrap QtCore.Q_ARG, поэтому в PyQt, где можно нормально использовать QMetaObject.invokeMethod вызвать слот (с аргументами) на Worker объекта из основного потока, вы не можете сделать это прямо в PySide и должны создать сигнал dunky (то есть Main.send_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_() 
+0

Я довольно новичок в программировании с резьбой, поэтому несите меня. Я переместил обработку файлов в отдельный поток, это то, что он висит в графическом интерфейсе, и я хочу разрешить пользователю «Отменить» процесс. Как открыть файл с вашим примером? Обычно я использую 'with open (имя файла, 'rb') как метод binaryFile:'. Возможно ли это с этим или мне нужно открыть файл, когда запускается 'QThread', а затем закрыть его при завершении? Я хочу убедиться, что файл закрыт должным образом. Я думаю, что я открою файл на '__init__' и обработаю его в' slot', а затем закрою, когда закончится нить? –

+0

Вы действительно хотите держать файл открытым все это время? Можете ли вы просто прочитать весь файл в памяти, а затем закрыть его? Можно открыть файл, выполнить некоторые операции, а затем закрыть его позже, но вы не можете приостановить операцию в середине контекста 'with', не приостанавливая цикл событий основного потока (который заморозит GUI). Можете ли вы просто переместить ** всю операцию, включая открытие файла ** в рабочий поток? Таким образом, нет причин постоянно отправлять данные назад и вперед между основным и рабочим потоками. –

+0

Проблема в том, что файл находится на большой стороне, я думаю, я мог бы загрузить все это в память. Одной из проблем, которые я пытаюсь сделать, является то, что программа, которую я заменяю (написанная на Java), занимает много времени, чтобы загрузить файл, прежде чем пользователь сможет его обработать. Поэтому я пытался избежать этого, загружая куски за раз, чтобы обработать. Я должен увидеть, сколько времени я получил, загрузив файл целиком. –