Объясните Python расширения многопоточности - PullRequest
3 голосов
/ 13 мая 2010

Интерпретатор Python имеет глобальную блокировку интерпретатора, и, насколько я понимаю, расширения должны получать ее в многопоточной среде. Но на странице Boost.Python HOWTO говорится, что функция расширения должна освободить GIL и повторно получить его при выходе.

Я хочу сопротивляться искушению угадать здесь, поэтому я хотел бы знать, какими должны быть шаблоны блокировки GIL в следующих сценариях:

  1. Расширение вызывается из python (предположительно работает в потоке python).
  2. И фоновый поток расширения вызывает обратно в Py_* функции.

И последний вопрос: почему в связанном документе говорится, что GIL должен быть выпущен и повторно приобретен?

1 Ответ

5 голосов
/ 13 мая 2010

Всякий раз, когда Python интерпретирует байт-код, GIL удерживается текущим работающим потоком. Никакой другой поток Python не может работать, пока ему не удастся получить GIL.

Когда интерпретатор вызвал собственный код, у этого кода есть две опции относительно GIL:

  1. Это ничего не может сделать.
  2. Он может высвободить GIL во время работы, а затем повторно получить его перед возвратом в Python

Если нативный код делает много обращений к среде исполнения Python, он должен принять опцию 1: вы никогда не сможете безопасно вызывать среду исполнения Python, если вы не держите GIL (с несколькими исключениями, такими как вызов для получения GIL, если вы его нет).

Если нативный код выполняет большую часть работы, которая никак не связана с Python, тогда вы можете использовать опцию 2: как только вы выпустите GIL, Python сможет запланировать другой поток Python, так что вы получите некоторый параллелизм. Если вы не освободите GIL, то ни один из других потоков Python не сможет выполняться, пока работает ваш Boost-код: поэтому в документах говорится, что вы должны освободить и повторно получить GIL.

Если вы пойдете этим путем, то вы должны быть осторожны, чтобы получить доступ ко всем функциям Py_* до того, как вы отпустите GIL или после того, как вы снова его получите. Это может означать, что вам нужно делать локальные копии данных, поскольку вы не можете безопасно обращаться к типам данных Python, таким как элементы списка или словаря, пока выпущен GIL.

Если ваш код Boost должен перезвонить в Python во время освобождения GIL, вам нужно получить GIL, сделать вызов, освободить GIL. Старайтесь избегать таких вызовов из потоков, которые не были созданы Python, поскольку они нуждаются в дополнительной работе для получения GIL.

...