Всякий раз, когда Python интерпретирует байт-код, GIL удерживается текущим работающим потоком. Никакой другой поток Python не может работать, пока ему не удастся получить GIL.
Когда интерпретатор вызвал собственный код, у этого кода есть две опции относительно GIL:
- Это ничего не может сделать.
- Он может высвободить 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.