Как манипулировать GIL, когда нужно выполнить много потоков? - PullRequest
0 голосов
/ 20 мая 2018

Насколько я понимаю, типичные манипуляции с GIL включают, например, блокировку операций ввода-вывода.Следовательно, хотелось бы снять блокировку перед операцией ввода-вывода и восстановить ее после ее завершения.

В настоящее время я сталкиваюсь с другим сценарием с расширением C: я создаю X окон, которые подвергаются воздействиюPython через класс Canvas.Когда метод show() вызывается для экземпляра, новый поток пользовательского интерфейса запускается с использованием PyThreads (с вызовом PyThread_start_new_thread).Этот новый поток отвечает за рисование в окне X с использованием кода Python, указанного в методе on_draw подкласса Canvas.Чистый цикл событий C запускается в главном потоке, который просто проверяет наличие событий в окне X и на данный момент захватывает только WM_DELETE_EVENT.

Так что у меня потенциально много потоков (по одному для каждогоОкно X), которые хотят выполнить код Python и основной поток, который вообще не выполняет код Python.

Как мне выпустить / получить GIL, чтобы потоки пользовательского интерфейса могли нормально входить в интерпретатор

Ответы [ 2 ]

0 голосов
/ 20 мая 2018

Я думаю, что проблема связана с тем фактом, что, на мой взгляд, официальная документация немного двусмысленна в смысле не-Python-созданных потоков .Цитата из него:

Когда потоки создаются с использованием специализированных API-интерфейсов Python (таких как модуль threading), с ними автоматически связывается состояние потока, и код показываетвыше, поэтому правильно.Однако, когда потоки создаются из C (например, сторонней библиотекой с собственным управлением потоками), они не содержат GIL и не имеют структуры состояний потоков для них.

Я выделил жирным шрифтом те части, которые мне кажутся неприятными.Как я уже говорил в OP, я звоню PyThread_start_new_thread.Хотя это создает новый поток из C, эта функция является не частью сторонней библиотеки, а выделенных API-интерфейсов Python (C).Исходя из этого предположения, я исключил, что мне действительно нужно было использовать парадигму PyGILState_Ensure/PyGILState_Release.

Насколько я могу судить по тому, что я видел в своих экспериментах, поток, созданный из C с (просто) PyThread_start_new_thread следует рассматривать как созданный не на Python поток .

0 голосов
/ 20 мая 2018

Правило простое: вам нужно держать GIL для доступа к машине Python (любой API, начинающийся с Py<...> и любой PyObject).

Итак, вы можете освободитьэто когда вам ничего не нужно.

Что-то еще, кроме этого, является фундаментальной проблемой детализации блокировки : потенциальные преимущества по сравнению с накладными расходами блокировки. Был эксперимент для Py 1.4, чтобы заменить GIL более детальными блокировками, которые потерпели неудачу именно потому, что накладные расходы оказались запредельными.

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


Придерживаясь этого правила,вы автоматически достигнете своей цели: всякий раз, когда поток не может продолжить работу (будь то ввод / вывод, сигнал от другого потока или даже time.sleep(), чтобы избежать занятого цикла), он снимает блокировку ипозволить другим потокам проходить вместо них.Механизм назначения GIL стремится быть справедливым (см. issue8299 для изучения того, насколько это справедливо), освобождая программиста от беспокойства по поводу любого смещения, возникающего исключительно из двигателя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...