Если вы пишете свое расширение на C ++, вы можете использовать RAII для простого и удобного написания кода, манипулирующего GIL. Я использую эту пару структурированных RAII:
namespace py {
namespace gil {
struct release {
PyThreadState* state;
bool active;
release()
:state(PyEval_SaveThread()), active(true)
{}
~release() { if (active) { restore(); } }
void restore() {
PyEval_RestoreThread(state);
active = false;
}
};
struct ensure {
PyGILState_STATE* state;
bool active;
ensure()
:state(PyGILState_Ensure()), active(true)
{}
~ensure() { if (active) { restore(); } }
void restore() {
PyGILState_Release(state);
active = false;
}
};
}
}
… позволяющий переключать GIL для данного блока (семантическим образом, который может показаться смутно знакомым для любого поклонника Pythonista из контекстного менеджера):
PyObject* YourPythonExtensionFunction(PyObject* self, PyObject* args) {
Py_SomeCAPICall(…); /// generally, if it starts with Py* it needs the GIL
Py_SomeOtherCall(…); /// ... there are exceptions, see the docs
{
py::gil::release nogil;
std::cout << "Faster and less block-y I/O" << std::endl
<< "can run inside this block -" << std::endl
<< "unimpeded by the GIL";
}
Py_EvenMoreAPICallsForWhichTheGILMustBeInPlace(…);
}
… На самом деле, лично я нахожу простоту расширения Python, а уровень контроля над внутренними структурами и состоянием - убийственная особенность.