Уведомления

Группа в Telegram: @pythonsu

#1 Май 19, 2019 09:11:47

RedBar
Зарегистрирован: 2019-05-19
Сообщения: 3
Репутация: +  0  -
Профиль   Отправить e-mail  

Не могу убить поток QThread

Добрый день!

Есть основная программа - интерфейс на 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
Т.е. поток живой, а хотелось бы, чтобы после Kill закрывался. Я предполагаю, что сигнал до потока не доходит.
Буду рад любой помощи.

Отредактировано RedBar (Май 19, 2019 09:13:10)

Офлайн

#2 Май 19, 2019 12:03:34

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2742
Репутация: +  183  -
Профиль   Отправить e-mail  

Не могу убить поток QThread

Ты не правильно используешь QThread. От него нужно унаследоваться и переопределить метод run в котором и будут происходить вычисления.

> Т.е. поток живой, а хотелось бы, чтобы после Kill закрывался.

Самый простой и надёжный способ остановить поток это в русную выставить флаг после проверки которого нужно завершать вычисления.



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#3 Июнь 29, 2019 20:16:32

RedBar
Зарегистрирован: 2019-05-19
Сообщения: 3
Репутация: +  0  -
Профиль   Отправить e-mail  

Не могу убить поток QThread

Rodegast
Ты не правильно используешь QThread. От него нужно унаследоваться и переопределить метод run в котором и будут происходить вычисления.> Т.е. поток живой, а хотелось бы, чтобы после Kill закрывался.Самый простой и надёжный способ остановить поток это в русную выставить флаг после проверки которого нужно завершать вычисления.

Вариант с переопределением run тоже был опробован. К сожалению, результат тот же.

Действительно разработчики рекомендуют выставить флаг внутри., но я так не могу сделать, так как у меня там по сути одна внешняя функция для научного расчёта, внутрь которой я не могу залезть.

Поэтому переделал под процессы в multiprocessing. Оставляю решение может кому пригодится.
 #!/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_())

Офлайн

#4 Июнь 30, 2019 01:30:24

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9849
Репутация: +  853  -
Профиль   Отправить e-mail  

Не могу убить поток QThread

Rodegast
Ты не правильно используешь QThread. От него нужно унаследоваться и переопределить метод run
Не, он правильно делает. Это всё выяснялось давно для C++/Qt, баба написала результат.
Тут писал пример.



Офлайн

#5 Июль 1, 2019 10:59:33

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2742
Репутация: +  183  -
Профиль   Отправить e-mail  

Не могу убить поток QThread

> Не, он правильно делает. Это всё выяснялось давно для C++/Qt, баба написала результат.

Я так думаю что программист должен руководствоваться официальной документацией, а не сведениями агентства ОБС



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#6 Июль 1, 2019 14:27:45

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9849
Репутация: +  853  -
Профиль   Отправить e-mail  

Не могу убить поток QThread

Rodegast
Я так думаю что программист должен руководствоваться официальной документацией
Ну не работает нифига из неё. Работало бы, никто бы не пытался эту проблему решить. Просто Qt сделана не идеально. Когда я перешёл на новый стиль, у меня сразу всё заработало и проблемы все исчезли.



Офлайн

#7 Июль 1, 2019 15:44:26

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2742
Репутация: +  183  -
Профиль   Отправить e-mail  

Не могу убить поток QThread

> Ну не работает нифига из неё.

У меня всё работает.

> Когда я перешёл на новый стиль, у меня сразу всё заработало и проблемы все исчезли.

Какое отношение к потокам имеет “новый стиль”?



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#8 Июль 2, 2019 00:20:43

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9849
Репутация: +  853  -
Профиль   Отправить e-mail  

Не могу убить поток QThread

Rodegast
У меня всё работает.
С тормозами, конечно. А у меня всё время генерятся новые потоки и убиваются через какое-то время - и всё пашет без тормозов и без таймеров. Хотя есть и таймеры, но они теперь работают не для того, чтобы многопоточностью управлять.

Rodegast
Какое отношение к потокам имеет “новый стиль”?
Новый стиль - это применение метода moveToThread(), а старый стиль (который кажется логичным) - это применение переопределения метода run().

Я не переопределяю метод run() вообще нигде и имею полностью многопоточную программу в Qt-фреймворке.



Офлайн

#9 Июль 2, 2019 11:11:22

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2742
Репутация: +  183  -
Профиль   Отправить e-mail  

Не могу убить поток QThread

> С тормозами, конечно.

Конечно нет. У меня с потоками и разу проблем не возникало.



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#10 Июль 20, 2019 22:18:00

@cckyi_boxxx
От:
Зарегистрирован: 2012-01-13
Сообщения: 181
Репутация: +  14  -
Профиль   Отправить e-mail  

Не могу убить поток QThread

пробовал еще такую методу, в классе создаю новый 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)

одного только не понимаю, почему не работает self.thr.run = self.srun, только через setattr выходит



Отредактировано @cckyi_boxxx (Июль 20, 2019 22:19:31)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version