Форум сайта python.su
Добрый день!
Есть основная программа - интерфейс на PyQt4.8, в ней при нажатии на кнопу запускается функция start(), внутри которой выполняется долгий научный расчёт. Так как расчёт выполняется иногда очень долго (часы), то я сделал ProgressBar с кнопкой, с нажатием по которой расчёт бы заканчивался. Расчёт я вынес в отдельный QThread, но у меня не получается его остановить.
def start(self): #Много подготовительных вычислений #Вычислительный поток self.worker = MyWorker() self.thread =QtCore.QThread() self.worker.moveToThread(self.thread) #Коннекты self.progressWindow.canceled.connect(self.threadKill) self.thread.finished.connect(self.threadFinished) self.connect(self.thread, QtCore.SIGNAL('started()'), self.worker.doWork) self.connect(self.worker, QtCore.SIGNAL('workFinished()'), self.thread, QtCore.SLOT('quit()')) print('Star', time()) self.progressWindow.show() self.thread.start()
class MyWorker(QtCore.QObject): def doWork(self): print('doWork') #Расчёт for i in range(1, 21): sleep(1) print('Сон', i) self.emit(QtCore.SIGNAL('workFinished()')) print('Сигнал')
def threadKill(self): """Принудительное завершение вычислительного потока""" #Завершаем вычислительный поток print('Kill', time()) self.thread.terminate() def threadFinished(self): """Завершение вычислительного потока""" print('Finish', time())
Start 1558245955.3263943 doWork Сон 1 Сон 2 Сон 3 Сон 4 Сон 5 Kill 1558245960.887371 Сон 6 Сон 7 Сон 8 Сон 9 Сон 10 Сон 11 Сон 12 Сон 13 Сон 14 Сон 15 Сон 16 Сон 17 Сон 18 Сон 19 Сон 20 Сигнал Finish 1558245975.3528898
Отредактировано RedBar (Май 19, 2019 09:13:10)
Офлайн
Ты не правильно используешь QThread. От него нужно унаследоваться и переопределить метод run в котором и будут происходить вычисления.
> Т.е. поток живой, а хотелось бы, чтобы после Kill закрывался.
Самый простой и надёжный способ остановить поток это в русную выставить флаг после проверки которого нужно завершать вычисления.
Офлайн
Rodegast
Ты не правильно используешь QThread. От него нужно унаследоваться и переопределить метод run в котором и будут происходить вычисления.> Т.е. поток живой, а хотелось бы, чтобы после Kill закрывался.Самый простой и надёжный способ остановить поток это в русную выставить флаг после проверки которого нужно завершать вычисления.
#!/usr/bin/python3 # -*- coding: UTF-8 -*- import multiprocessing from multiprocessing import Process, Manager from PyQt4 import QtCore, QtGui #from multiprocessing import Pool from time import sleep#, time def MyFunc(ns): print('Функция', ns.data) for i in range(1, 21): sleep(1) print('Дочерний поток', i) ns.result = [0, 0, 0] class MyWindow(QtGui.QWidget): def __init__(self, parent=None): super().__init__(parent) self.buttonStart = QtGui.QPushButton('СТАРТ') self.buttonStart.clicked.connect(self.start) self.progressWindow = QtGui.QProgressDialog(parent = self) self.progressWindow.setWindowModality(2)#Блокирует все окна self.progressWindow.setWindowTitle('Выполняется расчёт') self.progressWindow.setLabelText('Для сброса расчёта нажмите Отмена') self.progressWindow.setCancelButtonText('Отмена') self.progressWindow.setRange(0, 0) self.progressWindow.canceled.connect(self.stop) self.timer = QtCore.QTimer(parent = self) self.timer.setInterval(1000) self.timer.timeout.connect(self.timeToResult) self.buttonbox = QtGui.QVBoxLayout() self.buttonbox.addWidget(self.buttonStart) self.setLayout(self.buttonbox) def timeToResult(self): if not self.proc.is_alive(): if self.progressWindow.isVisible(): self.progressWindow.close() self.timer.stop() print('Выгружаем данные', self.ns.result) def start(self): self.progressWindow.show() self.timer.start() multiprocessing.set_start_method('spawn', force=True) mgr = Manager() self.ns = mgr.Namespace() self.ns.data = [1, 2, 3] self.ns.result = None self.proc = Process(target = MyFunc, args=(self.ns,)) self.proc.start() def stop(self): self.proc.terminate() print('СТОП') if __name__ == '__main__': import sys app = QtGui.QApplication(sys.argv) window = MyWindow() window.show() sys.exit(app.exec_())
Офлайн
RodegastНе, он правильно делает. Это всё выяснялось давно для C++/Qt, баба написала результат.
Ты не правильно используешь QThread. От него нужно унаследоваться и переопределить метод run
Офлайн
> Не, он правильно делает. Это всё выяснялось давно для C++/Qt, баба написала результат.
Я так думаю что программист должен руководствоваться официальной документацией, а не сведениями агентства ОБС
Офлайн
RodegastНу не работает нифига из неё. Работало бы, никто бы не пытался эту проблему решить. Просто Qt сделана не идеально. Когда я перешёл на новый стиль, у меня сразу всё заработало и проблемы все исчезли.
Я так думаю что программист должен руководствоваться официальной документацией
Офлайн
> Ну не работает нифига из неё.
У меня всё работает.
> Когда я перешёл на новый стиль, у меня сразу всё заработало и проблемы все исчезли.
Какое отношение к потокам имеет “новый стиль”?
Офлайн
RodegastС тормозами, конечно. А у меня всё время генерятся новые потоки и убиваются через какое-то время - и всё пашет без тормозов и без таймеров. Хотя есть и таймеры, но они теперь работают не для того, чтобы многопоточностью управлять.
У меня всё работает.
RodegastНовый стиль - это применение метода moveToThread(), а старый стиль (который кажется логичным) - это применение переопределения метода run().
Какое отношение к потокам имеет “новый стиль”?
Офлайн
> С тормозами, конечно.
Конечно нет. У меня с потоками и разу проблем не возникало.
Офлайн
пробовал еще такую методу, в классе создаю новый QThread, затем при помощи setattr приравниваю run к одному из методов класса родителя, и таким образом получаю аналог работы с переопределением метода run , ну и запускаю. Это разумеется не всегда но как дополнение к описанным вами методам сгодится.
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.thr = QThread() setattr(self.thr, 'run', self.srun) self.thr.start() def srun(self): while True: print('1') time.sleep(1)
Отредактировано @cckyi_boxxx (Июль 20, 2019 22:19:31)
Офлайн