Форум программистов, компьютерный форум, киберфорум
iamvic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
Путевые заметки в процессе познания Python и PyQt/PySide.
Помни - только тег CODE не портит код добавлением пробела в начало пустой строки.

Иллюстрация к вопросу о многопоточности в PyQt5.

Запись от iamvic размещена 01.01.2021 в 19:04
Показов 4589 Комментарии 6
Метки python

И всё-таки как-то очень долго я примеривался к тому, о чём говорится в https://evileg.com/ru/post/579/.
Очень хороший пример, но рамки поставленной там задачи не дают возможности полностью раскрыть
всю суть проблемы.

Ведь в документации https://doc.qt.io/qt-5/threads-technologies.html говорится буквально следующее:

- что перемещение объекта-исполнителя в дополнительный поток применяется в том случае,
если требуется по запросу неоднократно выполнять различные задачи в этом дополнительном потоке
и/или передавать им различные данные для обработки,

- что жить этот дополнительный поток должен постоянно ("permanent", в терминах документации,
судя по всему, от старта приложения до его завершения),

- что только в этом варианте запускается цикл обработки событий, который и позволяет объектам,
живущим в дополнительном потоке, принимать сигналы (в том числе и с нагрузкой в виде новых данных
для последующей обработки),

- что остальные варианты, использующие QThread (и одноразовый, и долгоживущий), обходятся
без обработки событий.

Всё хотелось разобраться - а как со всем этим управляться-то? Что можно делать? Что нельзя?
Какие заморочки вылезают? И прочее...

И всё как-то было недосуг, а тут, на Новый Год, как раз сошлись и место, и время, и желание, и возможности...
В результате наваялась, как оказалось, презабавнейшая поделка.
Очень интересно с ней было поиграться - узнал много нового.

Что там сделано:

- дополнительный поток поднят прямо в __main__. По-моему, там ему самое место с таким временем жизни.

- в поток перемещаются два объекта-исполнителя. А что мешает? В одном собраны задачи, которые рано или
поздно сами завершатся, а в другом — те, которые без вмешательства пользователя будут длиться вечно.
Сделано это с прицелом на то, чтобы можно было убедиться, что очереди обслуживают поток в целом,
а не отдельные объекты, живущие в нём,

- всё управление - в ручном режиме из меню главного окна приложения:
получение сведений о дополнительном потоке, его запуск, завершение и терминирование,
установка запроса на прерывание, запуск тестов и завершение работы приложения,

- всё происходящее (какая задача выполняется, какие сигналы отправлены, какие получены,
кто отправитель, в каком потоке он живёт и прочая) должным образом протоколируется и в режиме
"нажми на кнопку - получишь результат" отображается в центральном виджете главного окна приложения.

- по выходу из приложения весь собранный протокол дописывается в файл threadprobe.log домашнего каталога.

Записи протокола содержат некое описание произошедшего, включая имя объекта с именем метода/слота,
сгенерировашего запись, 16-ричный идентификатор этого объекта (в круглых скобках), 16-ричный идентификатор
потока, в котором живёт этот объект (в угловых скобках) и, возможно, 16-ричный идентификатор потока,
управляющего дополнительным потоком (в обрамлении эвёздочек).

Объект дополнительного потока и объекты, живущие в дополнительном потоке, формируя нагрузку,
отправляемую сигналами, помечают начало каждой строки символами --->, что позволяет отличить их в протоколе
от остальных записей. Этой же цели служит и цветовая дифференциация в окне просмотра протокола.

Пример протокола:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<0x22ea120> mainWin.to_start_thread() reported 01/01/2021 13:41:04
startSignal emitted
<0x22ea120> mainWin.on_check_started() reported 01/01/2021 13:41:04
testThread (0x2297a80) started
sender is testThread (0x2297a80)
<0x22ea120> mainWin.to_run_short() reported 01/01/2021 13:41:09
shortSignal emitted
<0x22ea120> mainWin.on_check_test() reported 01/01/2021 13:41:09
---> <0x2297a80> testFinite.shortTest() reported 01/01/2021 13:41:09
---> testFinite.shortTest() started
sender is testFinite (0x2297ad0)
<0x22ea120> mainWin.on_check_test() reported 01/01/2021 13:41:14
---> <0x2297a80> testFinite.shortTest() reported 01/01/2021 13:41:14
---> testFinite.shortTest() done
sender is testFinite (0x2297ad0)
Сравнение идентификатора объекта testThread (строка 4) и идентификатора потока, в котором живёт
объект testFinite (строки 9 и 13), позволяет говорить о том, что задание выполнялось именно
в дополнительном потоке.

Что нового узнал, пока гонял эту программку на разной технике под разными системами:

- можно завершить дополнительный поток, а потом повторно стартовать его,

- можно натолкать заданий в очередь нестартовавшего или уже завершённого дополнительного потока.
Они начнут выполняться после старта/рестарта потока в порядке очерёдности,

- завершение дополнительного потока обычно происходит после завершения текущего задания.
Однако, если на момент старта/рестарта потока в очереди уже присутствовали задания, то поток завершится
только после выполнения всех этих заданий,

- терминирование завершает дополнительный поток немедленно и делает неработоспобным целиком объект,
живущий в дополнительном потоке, чьё задание было ранее терминировано.
А вот задания из другого объекта, не подвергавшегося терминированию, вполне могут выполняться после
рестарта потока. Но, тут - лотерея, всё зависит от захваченных ресурсов. Здесь-то только мьютексы взведённые
остаются - и всё проскакивает, а как это будет в реальной задаче...
По-моему, лучший выход - завершить работу приложения в этом случае,

- терминирование сопровождается выдачей сообщения об ошибке.
Linux отплёвывается текстом в stdout сразу при выполнении QThread.terminate() и более никак себя не проявляет,
Windows терпит либо до завершения дополнительного потока после рестарта и тогда, выдав сообщение, сносит
приложение, либо до закрытия приложения и тогда выдаёт ошибку уже после закрытия окна приложения,

- можно ещё запустить приложение с параметром (параметр любой, лишь бы он был).
Тогда в терминальную сессию вывалится печать контрольных точек.
Можно понаблюдать, как GUI скачет из одного потока в другой в процессе инициализации.
Это к вопросу определения GUI-потока

Вроде, всё. С Новым Годом!

(исходник в прилагаемом архиве)
(см. обновление https://www.cyberforum.ru/blog... g6949.html)
Вложения
Тип файла: zip qthread_probe.zip (6.4 Кб, 2099 просмотров)
Метки python
Размещено в Памятка
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 6
Комментарии
  1. Старый комментарий
    Аватар для Avazart
    - что перемещение объекта-исполнителя в дополнительный поток применяется в том случае,
    если требуется по запросу неоднократно выполнять различные задачи в этом дополнительном потоке
    и/или передавать им различные данные для обработки,
    Нет. Думаю так не стоит воспринимать QThread.
    Стоит воспринимать как есть т.е. как должное, что есть такой интерфейс который подразумевает сам "класс потока" и "класс рабочего" (worker).
    Для разные данных можно создавать разные объекты а не использовать одно и тоже, да и есть для этого другие средства.

    Кроме того актуален вопрос для чего Вам потоки?
    Более того вопрос усложняется спецификой языка Python так как там потоки будут блокироваться GIL и будет работать не совсем так как для С++.


    Всё хотелось разобраться - а как со всем этим управляться-то? Что можно делать? Что нельзя?
    Какие заморочки вылезают? И прочее...
    Для начала стоит разобраться что такое сигнал/слот и что такое цикл обработки событий (event loop).
    Как это то с чего стоит начинать изучение Qt и что жизненно важно для понимания того как работают GUI приложения.

    (исходник в прилагаемом архиве)
    Исходники стоит размещать на github а не архивом на форуме.
    Запись от Avazart размещена 03.01.2021 в 18:46 Avazart вне форума
  2. Старый комментарий
    Avazart, искреннее спасибо за участие! Мне, действительно, ещё пахать и пахать

    Но, по крайней мере, даже не написание программки, а игры с этим получившимся тренажёрчиком
    помогли мне понять о чём всё-таки идёт речь в следующих статьях и, самое главное,
    в комментариях к ним:

    https://www.qt.io/blog/2010/06... g-it-wrong
    https://woboq.com/blog/qthread... wrong.html
    http://blog.debao.me/2013/08/h... ay-part-1/
    http://blog.debao.me/2013/08/h... ay-part-2/

    Всё, о чём там говорится, теперь для меня не пустой звук. после того, как я на тренажёре
    наступил на все эти грабли.

    А до размещения на github я ещё и не дорос пока Да и тут всё-таки блог, хотя и на форуме.
    Это же не портит форум. И ответственные лица не возражают.
    Запись от iamvic размещена 04.01.2021 в 10:59 iamvic вне форума
  3. Старый комментарий
    Аватар для Avazart
    А до размещения на github я ещё и не дорос пока
    Гит сразу нужно учить. Если не доросли идите в садик потом в школу ... потом программировать.


    В первой статьи говориться что использовать moveToThread(self); не верно т.е. помещать поток в самого себя.
    Эту статью можно вовсе не читать. Стоит сразу смотреть примеры из официальной документации и тогда таких ошибок вовсе не будет.

    Остальные стать про то что опять же стоит отдавать предпочтению QThread + Worker класс перед прямым наследованием от QThread.
    При чем староватые статьи.

    В общем случае стоит руководствоваться правилом: в любой непонятной ситуации сначала смотри в официальную документацию, к тому же у Qt она очень хорошего качества (сравнительно) проблема лишь в том что там С++ а не Python.

    а игры с этим получившимся тренажёрчиком
    Игры возможно стоит писать лучше используя PyGame, а не PyQt.
    PyQt это все же GUI программы.
    Запись от Avazart размещена 04.01.2021 в 18:57 Avazart вне форума
  4. Старый комментарий
    Цитата Сообщение от Avazart
    идите в садик потом в школу ... потом программировать.
    Avazart, вы отстали от жизни!

    В нашей младшей группе детского сада уже все - программисты. И все - на удалёнке,
    можно даже сказать, фрилансеры
    И, в силу присущей возрасту конкретности мышления, хотелось бы услышать критику и обсуждение
    именно тех решений, которые использованы в прилагаемой программе, а не общевдохновляющие лозунги
    типа "иди тудо - незнамо кудо, учи то - незнамо что".

    Если у вас есть замечания по тексту программы, то не стесняйсь - ткните пальцем в проблемное место
    и доходчиво объясните почему. Ваше замечание будет с благодарностью принято.
    Если у вас, кроме педагогического зуда, ничего нет, то забейте, не чешите, проходите мимо.
    Можете ещё оценочку выставить и нажать кнопочку "пожаловаться". Тогда, вероятно, группа специально
    обученных модераторов может принять решение вырезать этот блог.

    Правила не запрещают вам чувствовать себя в чужом блоге, как дома, но забывать о том, что вы в гостях,
    наверное, не следует? Всё-таки есть тонкие различия между форумом и блогом. У вас же опыта больше,
    вы же это наверняка понимаете?
    Запись от iamvic размещена 04.01.2021 в 23:13 iamvic вне форума
  5. Старый комментарий
    Аватар для Avazart
    Если у вас есть замечания по тексту программы,
    Я не умею смотреть исходники с архивов
    Запись от Avazart размещена 05.01.2021 в 12:57 Avazart вне форума
  6. Старый комментарий
    Аватар для Avazart
    ...
    Запись от Avazart размещена 05.01.2021 в 12:59 Avazart вне форума
 
Новые блоги и статьи
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru