Ответ: в вашем случае я не вижу необходимости использовать QThread
.
TL;DR;
Когда мне нужно использовать другой поток в контексте графического интерфейса?
Только один поток должен использоваться, когда какая-то задача может заблокировать основной поток, называемыйпоток GUI, и блокировка вызвана, потому что задача занимает много времени, препятствуя тому, чтобы цикл событий GUI нормально выполнял свою работу.Все современные графические интерфейсы выполняются в EventLop, что позволяет получать уведомления от ОС, такие как клавиатура, мышь и т. Д., А также позволяет изменять состояние графического интерфейса в зависимости от пользователя.
ВВ вашем случае я не вижу какой-либо тяжелой задачи, поэтому я не вижу необходимости в QThread, я действительно не знаю, что это за задача, которую вы хотите периодически запускать.
Предполагая, что у вас есть задача, которая потребляетмного времени, скажем 30 секунд, и вы должны делать это каждые полчаса, тогда нить необходима.и в вашем случае вы хотите использовать для него QTimer.
Давайте разберёмся по частям, QTimer
- это класс, который наследуется от QObject
, а QObject
принадлежит к тому же, что и родительский.и если у него нет родителя, он принадлежит потоку, в котором он был создан.С другой стороны, часто думают, что QThread
- это поток в Qt , но это не так, QThread
- это класс, который позволяет обрабатывать жизненный цикл собственного потока, иэто ясно указано в документах : Класс QThread предоставляет независимый от платформы способ управления потоками .
Зная выше, давайтепроанализируйте ваш код:
timer = QTimer(self)
В вышеприведенном коде self является родителем QTimer, а self является QThread
, поэтому QTimer
принадлежит потоку родителя QThread
или где QThread былсоздано, а не потоку, который обрабатывает QThread
.
Тогда давайте посмотрим код, в котором было создано QThread
:
worker = WorkerThread()
Как мы видим, QThread
не имеет родителя, тогдаQThread
принадлежит потоку, в котором он был создан, то есть QThread
принадлежит основному потоку, и, следовательно, его QTimer
дочерний элемент также принадлежит основному потоку.Также обратите внимание, что новый поток, который обрабатывает QThread
, имеет только область действия метода run()
, если метод находится в другом месте, относится к полю, где был создан QThread
, со всем вышеперечисленным мы видим, что вывод кодаправильно, и QThread.sleep(5)
запускается в главном потоке, вызывая сбой Eventloop и графический интерфейс пользователя.
Таким образом, решение состоит в том, чтобы удалить родительский элемент QTimer
, чтобы поток, к которому он принадлежит, былодин из метода run()
, и переместите рабочую функцию в тот же метод.С другой стороны, это плохая практика - создавать статические атрибуты без необходимости, учитывая, что приведенный выше код выглядит следующим образом:
import sys
import threading
from PyQt5.QtCore import QThread, QTimer
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget
class WorkerThread(QThread):
def run(self):
def work():
print("working from :" + str(threading.get_ident()))
QThread.sleep(5)
print("thread started from :" + str(threading.get_ident()))
timer = QTimer()
timer.timeout.connect(work)
timer.start(10000)
self.exec_()
class MyGui(QWidget):
def __init__(self):
super().__init__()
self.initUi()
self.worker = WorkerThread(self)
print("Starting worker from :" + str(threading.get_ident()))
self.worker.start()
def initUi(self):
self.setGeometry(500, 500, 300, 300)
self.pb = QPushButton("Button", self)
self.pb.move(50, 50)
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = MyGui()
gui.show()
sys.exit(app.exec_())
Вывод:
Starting worker from :140068367037952
thread started from :140067808999168
working from :140067808999168
working from :140067808999168
Замечания:
Тяжелая задача, которая была эмулирована, составляет 5 секунд, и эта задача должна выполняться каждые 10 секунд.Если ваша задача занимает больше времени, чем период, вы должны создать другие потоки.
Если ваша задача состоит в выполнении периодической задачи, которая не так трудна, как показ времени, не используйте новые потоки, потому чтоВы добавляете сложность к простой задаче, кроме того, это может сделать этап отладки и тестирования более сложным.