Путевые заметки в процессе познания Python и PyQt/PySide.
Помни - только тег CODE не портит код добавлением пробела в начало пустой строки.
Помни - только тег CODE не портит код добавлением пробела в начало пустой строки.
Иллюстрация к вопросу о многопоточности в PyQt5.
Запись от iamvic размещена 01.01.2021 в 19:04
Показов 4493
Комментарии 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-ричный идентификатор потока, управляющего дополнительным потоком (в обрамлении эвёздочек). Объект дополнительного потока и объекты, живущие в дополнительном потоке, формируя нагрузку, отправляемую сигналами, помечают начало каждой строки символами --->, что позволяет отличить их в протоколе от остальных записей. Этой же цели служит и цветовая дифференциация в окне просмотра протокола. Пример протокола:
объект testFinite (строки 9 и 13), позволяет говорить о том, что задание выполнялось именно в дополнительном потоке. Что нового узнал, пока гонял эту программку на разной технике под разными системами: - можно завершить дополнительный поток, а потом повторно стартовать его, - можно натолкать заданий в очередь нестартовавшего или уже завершённого дополнительного потока. Они начнут выполняться после старта/рестарта потока в порядке очерёдности, - завершение дополнительного потока обычно происходит после завершения текущего задания. Однако, если на момент старта/рестарта потока в очереди уже присутствовали задания, то поток завершится только после выполнения всех этих заданий, - терминирование завершает дополнительный поток немедленно и делает неработоспобным целиком объект, живущий в дополнительном потоке, чьё задание было ранее терминировано. А вот задания из другого объекта, не подвергавшегося терминированию, вполне могут выполняться после рестарта потока. Но, тут - лотерея, всё зависит от захваченных ресурсов. Здесь-то только мьютексы взведённые остаются - и всё проскакивает, а как это будет в реальной задаче... По-моему, лучший выход - завершить работу приложения в этом случае, - терминирование сопровождается выдачей сообщения об ошибке. Linux отплёвывается текстом в stdout сразу при выполнении QThread.terminate() и более никак себя не проявляет, Windows терпит либо до завершения дополнительного потока после рестарта и тогда, выдав сообщение, сносит приложение, либо до закрытия приложения и тогда выдаёт ошибку уже после закрытия окна приложения, - можно ещё запустить приложение с параметром (параметр любой, лишь бы он был). Тогда в терминальную сессию вывалится печать контрольных точек. Можно понаблюдать, как GUI скачет из одного потока в другой в процессе инициализации. Это к вопросу определения GUI-потока ![]() Вроде, всё. С Новым Годом! (исходник в прилагаемом архиве) (см. обновление https://www.cyberforum.ru/blog... g6949.html) | |||||
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 6
Комментарии
-
Нет. Думаю так не стоит воспринимать QThread.
Стоит воспринимать как есть т.е. как должное, что есть такой интерфейс который подразумевает сам "класс потока" и "класс рабочего" (worker).
Для разные данных можно создавать разные объекты а не использовать одно и тоже, да и есть для этого другие средства.
Кроме того актуален вопрос для чего Вам потоки?
Более того вопрос усложняется спецификой языка Python так как там потоки будут блокироваться GIL и будет работать не совсем так как для С++.
Для начала стоит разобраться что такое сигнал/слот и что такое цикл обработки событий (event loop).
Как это то с чего стоит начинать изучение Qt и что жизненно важно для понимания того как работают GUI приложения.
Исходники стоит размещать на github а не архивом на форуме.Запись от Avazart размещена 03.01.2021 в 18:46
-
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
-
Гит сразу нужно учить. Если не доросли идите в садик потом в школу ... потом программировать.
В первой статьи говориться что использовать moveToThread(self); не верно т.е. помещать поток в самого себя.
Эту статью можно вовсе не читать. Стоит сразу смотреть примеры из официальной документации и тогда таких ошибок вовсе не будет.
Остальные стать про то что опять же стоит отдавать предпочтению QThread + Worker класс перед прямым наследованием от QThread.
При чем староватые статьи.
В общем случае стоит руководствоваться правилом: в любой непонятной ситуации сначала смотри в официальную документацию, к тому же у Qt она очень хорошего качества (сравнительно) проблема лишь в том что там С++ а не Python.
Игры возможно стоит писать лучше используя PyGame, а не PyQt.
PyQt это все же GUI программы.Запись от Avazart размещена 04.01.2021 в 18:57
-
Avazart, вы отстали от жизни!
Сообщение от Avazart
В нашей младшей группе детского сада уже все - программисты. И все - на удалёнке,
можно даже сказать, фрилансеры
И, в силу присущей возрасту конкретности мышления, хотелось бы услышать критику и обсуждение
именно тех решений, которые использованы в прилагаемой программе, а не общевдохновляющие лозунги
типа "иди тудо - незнамо кудо, учи то - незнамо что".
Если у вас есть замечания по тексту программы, то не стесняйсь - ткните пальцем в проблемное место
и доходчиво объясните почему. Ваше замечание будет с благодарностью принято.
Если у вас, кроме педагогического зуда, ничего нет, то забейте, не чешите, проходите мимо.
Можете ещё оценочку выставить и нажать кнопочку "пожаловаться". Тогда, вероятно, группа специально
обученных модераторов может принять решение вырезать этот блог.
Правила не запрещают вам чувствовать себя в чужом блоге, как дома, но забывать о том, что вы в гостях,
наверное, не следует? Всё-таки есть тонкие различия между форумом и блогом. У вас же опыта больше,
вы же это наверняка понимаете?Запись от iamvic размещена 04.01.2021 в 23:13
-
Запись от Avazart размещена 05.01.2021 в 12:57
-
Запись от Avazart размещена 05.01.2021 в 12:59




