Параллелизм: Глобальные блокировки интерпретатора влияют на расширения Python, написанные на C / C ++? - PullRequest
22 голосов
/ 16 марта 2009

Одна из самых сильных сторон Python - это простота написания расширений C и C ++ для ускорения процессорных частей кода. Могут ли эти расширения избежать Глобальной блокировки интерпретатора или они также ограничены GIL? Если нет, то эта «простота расширения» является еще более убийственной функцией, чем я раньше предполагал. Я подозреваю, что ответ не простой да-или-нет, но я не уверен, поэтому я задаю вопрос здесь, на StackOverflow.

Ответы [ 4 ]

19 голосов
/ 16 марта 2009

Да, вызовы расширений C (подпрограммы C, вызываемые из Python) все еще подчиняются GIL.

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

Для получения информации взгляните на макросы Py_BEGIN_ALLOW_THREADS и Py_END_ALLOW_THREADS: http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock

8 голосов
/ 16 марта 2009

C / C ++ расширения для Python не связаны GIL. Тем не менее, вам действительно нужно знать, что вы делаете. С http://docs.python.org/c-api/init.html:

Глобальная блокировка интерпретатора используется для защиты указателя на текущее состояние потока. При снятии блокировки и сохранении состояния потока указатель текущего состояния потока должен быть получен до снятия блокировки (поскольку другой поток может немедленно получить блокировку и сохранить собственное состояние потока в глобальной переменной). И наоборот, при получении блокировки и восстановлении состояния потока блокировка должна быть получена до сохранения указателя состояния потока.

Почему я так подробно рассказываю об этом? Потому что, когда потоки создаются из C, они не имеют глобальной блокировки интерпретатора и не имеют структуры данных состояния потока для них. Такие потоки должны запускаться самостоятельно, сначала создав структуру данных состояния потока, затем получив блокировку и, наконец, сохраняя указатель состояния потока, прежде чем они смогут начать использовать API Python / C. По завершении они должны сбросить указатель состояния потока, снять блокировку и, наконец, освободить структуру данных состояния потока.

1 голос
/ 08 апреля 2016

Если вы пишете свое расширение на 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, а уровень контроля над внутренними структурами и состоянием - убийственная особенность.

0 голосов
/ 09 апреля 2009

Ознакомьтесь с Cython, он имеет синтаксис, аналогичный Python, но с несколькими конструкциями, такими как "cdef", функции быстрого доступа к numy и оператор "with nogil" (который делает то, что говорит).

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