Форум программистов, компьютерный форум, киберфорум
Python для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/15: Рейтинг темы: голосов - 15, средняя оценка - 5.00
 Аватар для rialbat
2 / 2 / 0
Регистрация: 14.09.2018
Сообщений: 47

Блокировка интерфейса pyside (Qt) при реализации многопоточны­­­­х приложений

15.08.2022, 16:01. Показов 3735. Ответов 9

Студворк — интернет-сервис помощи студентам
Здравствуйте. Реализовал приложение для опроса (пинговки) серверов, при помощи TCP запросов. Отправка запросов и прием ответов осуществляются в многопоточном режиме:
Python
1
2
3
with ThreadPoolExecutor(max_workers=self._threads) as executor:
    for ip in ipPool:
    executor.submit(self.searchForServers, ip)
Программа работает, однако не удается собирать статистику. При выполнении программы, графический интерфейс перестает откликаться. Из-за чего статистические данные не обновляются вплоть до завершения всех потоков. Как я понимаю, это происходит из-за использования технологии GIL в python.
Возможно ли это побороть каким-то образом? Обновление статистических данных также происходит в отдельном потоке (каждую секунду, пока не завершатся основные потоки), однако визуально это происходит единожды, после завершения всех потоков.
Изображения
 
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
15.08.2022, 16:01
Ответы с готовыми решениями:

Проблема в pyTelegramBo­tA­pi
Я хотел сделать свою игру в телеграм боте, проблема заключается в том что (скрин №1, скрин №2) код работает просто отлично, а когда...

MutationObse­­­rver не перехватывае­­­т программные события
Подскажите пожалуйста, вот ставлю MutationObserver на элемент к примеру ввода. Затем просто веду курсор мышки на элемент ввода и...

Не получается изменить имя родительског­­­­­о блока в цикле массива
Есть функция, которая печатает имя пользователя и его числа. При выводе результата в echo(я эти две строки пометил комментами) я...

9
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939
15.08.2022, 16:56
Лучший ответ Сообщение было отмечено rialbat как решение

Решение

Цитата Сообщение от rialbat Посмотреть сообщение
При выполнении программы, графический интерфейс перестает откликаться.
Вы видимо сам ThreadPoolExecutor запускаете в основном потоке GUI.

Добавлено через 21 секунду
Сейчас пример наковыряю)

Добавлено через 10 минут
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import sys
import time
 
from PyQt5.QtCore import QRunnable, QThreadPool, QTimer, pyqtSlot
from PyQt5.QtWidgets import (
    QApplication,
    QLabel,
    QMainWindow,
    QPushButton,
    QVBoxLayout,
    QWidget,
)
 
 
class Worker(QRunnable):
    @pyqtSlot()
    def run(self):
        print("Thread start, вы что-то делаете в течении 5 секунд, вне основного потока")
        time.sleep(5)
        print("Thread complete, завершили действие")
 
 
 
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
 
        self.threadpool = QThreadPool()
 
        self.counter = 0 # счетчик, который мы обновляем, в основном потоке
 
        layout = QVBoxLayout()
 
        self.l = QLabel("Start")
        b = QPushButton("Нажать")
        b.pressed.connect(self.my_proccess)
 
        layout.addWidget(self.l)
        layout.addWidget(b)
 
        w = QWidget()
        w.setLayout(layout)
 
        self.setCentralWidget(w)
 
        self.show()
 
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.recurring_timer)
        self.timer.start()
 
 
    def my_proccess(self):
        worker = Worker()
        self.threadpool.start(worker)
 
 
    def recurring_timer(self):
        self.counter += 1
        self.l.setText("Счетчик: %d" % self.counter)
 
 
app = QApplication(sys.argv)
window = MainWindow()
app.exec_()
Добавлено через 2 минуты
rialbat, если запустите этот код и нажмете кнопку, то запустится Worker по времени 5 секунд, но при этом счетчик в основном потоке продолжит обновляется. Мне кажется это то что +/- Вам было нужно.

Добавлено через 1 минуту

Не по теме:

pyside6 у меня нет, но там все так же, возможны незначительные изменения

3
 Аватар для rialbat
2 / 2 / 0
Регистрация: 14.09.2018
Сообщений: 47
15.08.2022, 18:54  [ТС]
Буду пробовать, спасибо. Отпишусь, как что-нибудь получится.

Добавлено через 57 минут
Сделал как у Вас, вроде работает, однако не совсем понял, как задать конкретное число потоков в пуле (или может максимальное число потоков).
То есть допустим мне необходимо проверить 1 000 ip адресов, я предполагаю это организовать в 100 потоков, как это можно сделать с QThreadPool?
Я следующим образом описал класс Worker:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Worker(QtCore.QRunnable):
    def __init__(self, ip, port, timeout):
        super().__init__()
        self._ip = ip
        self._specificPort = port
        self._specificTimeOut = timeout
 
    @QtCore.Slot()
    def run(self):
        lServerStatus = ServerStatus(self._ip, self._specificPort, self._specificTimeOut)
 
        try:
            serverResponse = lServerStatus.get_status()
        except Exception:
            pass
        else:
            print("Thread Worked")
            return serverResponse
И мне необходимо сделать что-то такое, в 100 потоков:
Python
1
2
3
for ip in ipPool:
    worker = Worker(ip, self._specificPort, self._specificTimeOut)
    self._threadPool.start(worker)
0
 Аватар для rialbat
2 / 2 / 0
Регистрация: 14.09.2018
Сообщений: 47
15.08.2022, 20:21  [ТС]
На данный момент реализация выполнения потоков выглядит следующим образом:
Python
1
2
3
self._threadPool.setMaxThreadCount(self._threads)
for ip in ipPool:
    self._threadPool.start(Worker(ip, self._specificPort, self._specificTimeOut))
При запуске выполняет 5 задач.
Миниатюры
Блокировка интерфейса pyside (Qt) при реализации многопоточны­­­­х приложений  
0
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939
16.08.2022, 08:41
rialbat, я всегда запускал qthreadpool с настройками по умолчанию, не меняя максимальное количество потоков. Но можете посмотреть в документации, там вроде такое можно сделать:

Call maxThreadCount() to query the maximum number of threads to be used. If needed, you can change the limit with setMaxThreadCount() . The default maxThreadCount() is idealThreadCount() . The activeThreadCount() function returns the number of threads currently doing work.

см.тут

Добавлено через 1 час 29 минут
Цитата Сообщение от Михалыч Посмотреть сообщение
там вроде такое можно сделать
А может и не можно) Я если честно пока читал, совсем запутался.

Добавлено через 13 минут
Цитата Сообщение от rialbat Посмотреть сообщение
И мне необходимо сделать что-то такое, в 100 потоков:
Может более опытные товарищи подскажут, как такое делается.

Но мне кажется, потоки ограничены возможностью самого компа (например мой запускает 12 шт.), т.е. метод setMaxThreadCount представляет максимальное количество потоков, используемых пулом потоков, но эта штука ограничена idealThreadCount которое возвращает идеальное количество потоков, которые могут быть запущены в системе.
0
 Аватар для rialbat
2 / 2 / 0
Регистрация: 14.09.2018
Сообщений: 47
16.08.2022, 10:06  [ТС]
С этим разобрался, спасибо. Вроде работает как надо, правда результат выполнения функции (run) потоком можно вернуть только посредством эмита сигнала, я правильно понимаю? Или есть более грамотные ревеня?
0
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939
16.08.2022, 10:24
rialbat, сам пользуюсь вот такой конструкцией:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import random
import sys
import time
 
from PyQt5.QtCore import (
    QObject,
    QRunnable,
    QThreadPool,
    QTimer,
    pyqtSignal,
    pyqtSlot,
)
from PyQt5.QtWidgets import (
    QApplication,
    QLabel,
    QMainWindow,
    QPushButton,
    QVBoxLayout,
    QWidget,
)
 
 
class WorkerSignals(QObject):
    finished = pyqtSignal()
    error = pyqtSignal(str)
    result = pyqtSignal(dict)
 
 
 
class Worker(QRunnable):
    def __init__(self, iterations=5):
        super().__init__()
        self.signals = WorkerSignals()  
        self.iterations = iterations
 
    @pyqtSlot()
    def run(self):
        try:
            for n in range(self.iterations):
                time.sleep(0.01)
                v = 5 / (40 - n)
 
        except Exception as e:
            self.signals.error.emit(str(e))
 
        else:
            self.signals.finished.emit()
            self.signals.result.emit({"n": n, "value": v})
 
 
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
 
        self.threadpool = QThreadPool()
        print(
            "Multithreading with maximum %d threads"
            % self.threadpool.maxThreadCount()
        )
 
        self.counter = 0
 
        layout = QVBoxLayout()
 
        self.l = QLabel("Start")
        b = QPushButton("DANGER!")
        b.pressed.connect(self.oh_no)
 
        layout.addWidget(self.l)
        layout.addWidget(b)
 
        w = QWidget()
        w.setLayout(layout)
 
        self.setCentralWidget(w)
 
        self.show()
 
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.recurring_timer)
        self.timer.start()
 
    def oh_no(self):
        worker = Worker(iterations=random.randint(10, 50))
        worker.signals.result.connect(self.worker_output)
        worker.signals.finished.connect(self.worker_complete)
        worker.signals.error.connect(self.worker_error)
        self.threadpool.start(worker)
 
    def worker_output(self, s):
        print("RESULT", s)
 
    def worker_complete(self):
        print("THREAD COMPLETE!")
 
    def worker_error(self, t):
        print("ERROR: %s" % t)
 
    def recurring_timer(self):
        self.counter += 1
        self.l.setText("Counter: %d" % self.counter)
 
 
app = QApplication(sys.argv)
window = MainWindow()
app.exec_()
Добавлено через 1 минуту
Цитата Сообщение от rialbat Посмотреть сообщение
С этим разобрался, спасибо.
У Вас получилось сделать 100 потоков?
1
 Аватар для rialbat
2 / 2 / 0
Регистрация: 14.09.2018
Сообщений: 47
16.08.2022, 10:29  [ТС]
Понял Вас, тогда тоже через сигнал/слот. систему сделаю. Число потоков регулируется через GUI и устанавливается при помощи (self._threadPool.setMaxThreadCount(self ._threads)). Мне сначала казалось, что решение работает медленнее, чем через питоновские потоки, но вроде как правильно.
1
 Аватар для Михалыч
1011 / 355 / 59
Регистрация: 28.02.2013
Сообщений: 939
16.08.2022, 10:40
Цитата Сообщение от rialbat Посмотреть сообщение
Или есть более грамотные ревеня?
В этой книге есть целая глава с примерами на эту тему, мне лично понравилась)
Как раз есть по pyqt6, может там что-то новое появилось, я читал только по pyqt5.
0
 Аватар для rialbat
2 / 2 / 0
Регистрация: 14.09.2018
Сообщений: 47
16.08.2022, 14:24  [ТС]
Спасибо, посмотрю!

Добавлено через 3 часа 38 минут
Организовал работы программы по системе сигнал/слот и наткнулся на одну проблему. Если для каждого из проверяемых ip адресов создать объект класса Worker, а затем подключить его сигналы к слотам основного класса, таким образом:
Python
1
2
3
4
5
6
for ip in ipPool:
    worker = Worker(ip, self._specificPort, self._specificTimeOut)
    worker.signals.result.connect(self.receiveResponse)
    worker.signals.updateStats.connect(self.updateStatsLabels)
    self._threadPool.start(worker)
    self._checked = self._checked + 1
То получаем ограничение окало 1700 адресов. При использовании большего пула программа вылетает с ошибкой. Если не подключать сигналы, то ошибка не возникает и программа работает нормально при любом количестве адресов.
Я пробовал создать пул рабочих, равный количеству потоков в программе. А затем переопределять атрибут ip для каждого из объектов при назначении потоков:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for _ in range(self._threads):
    worker = Worker('', self._specificPort, self._specificTimeOut)
    worker.signals.result.connect(self.receiveResponse)
    worker.signals.updateStats.connect(self.updateStatsLabels)
    workersPool.append(worker)
 
curIp = 0
self._threadPool.setMaxThreadCount(self._threads)
for ip in ipPool:
    workersPool[curIp].setIp(ip)
    self._threadPool.start(workersPool[curIp])
    if curIp + 1 < self._threads:
        curIp = curIp + 1
    else:
        curIp = 0
    self._checked = self._checked + 1
Но в таком случае программа вылетает при достижении ip, равного количеству потоков в программе...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
16.08.2022, 14:24
Помогаю со студенческими работами здесь

Найти подстановку, при которой заданное множ-во дизъюнктов~P(x)~Q(g(a),y)Q(x,f(x))∨R(y)P(x)∨Q(x,f(­­­x))становится невыполн
Найти подстановку, при которой заданное множество дизъюнктов ~P(x) ~Q(g(a),y) Q(x,f(x))∨R(y) P(x)∨Q(x,f(x)) становится...

STEAM VR , Liv, синхронизаци­­­­­­­я видео в реальности и Vr( tilt brush )
Здравствуйте, у меня задача настроить качественную запись видео художника рисующего в vr ( в программах tilt brush , adobe medium в очках...

Неисправност­­­ь планок SDRAM?
Из того, что нашлось в закромах, получилась ретросборка на мат. плате с 370-м сокетом, докупил к ней две планки SDRAM PC-133 по 256 Мб...

Видеорегиста­­­тор NVR8016
Здравствуйте Помогите сбросить пароль на видеорегистаторе NVR8016

Ошибка необработанное исключение System.ComponentModel.Win32Exc­­­eption
Всем здравствуйте! Писал для себя программу, в процессе промежуточной отладки заметил, что после появления блока while выходит эксепшен: ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
Отображение реквизитов в документе по условию и контроль их заполнения
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеСпецтехники", разработанного в конфигурации КА2. Данный документ берёт данные из другого нетипового документа. . .
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизитов табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: 1. Реализовать контроль заполнения реквизита. . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
Программная установка даты и запрет ее изменения
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: при создании документов установить период списания автоматически. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru