Python не выпускает GIL, когда вы запускаете код C (если только вы не сообщите об этом или не вызовете выполнение кода Python — см. предупреждение внизу!). Он освобождает GIL только непосредственно перед инструкцией байт-кода (не во время), и с точки зрения интерпретатора выполнение функции C является частью выполнения CALL_FUNCTION
байт-кода.*
(к сожалению, я не могу найти ссылку на этот абзац в настоящее время , но я почти уверен, что это правильно)
Поэтому, если вы не сделаете что-то конкретное, ваш код C будет единственным запущенным потоком, и поэтому любая операция, которую вы выполняете в нем, должна быть потокобезопасной.
Если вы специально хотите выпустить GIL — например, потому что вы делаете длинные вычисления, которые не мешают Python, читаете из файла или спите, ожидая, что что-то еще произойдет — тогда самый простой способ — это сделать < a href="https://docs.python.org/3/c-api/init.html#releasing-the-gil-from-extension-code" rel="nofollow noreferrer">Py_BEGIN_ALLOW_THREADS
, затем Py_END_ALLOW_THREADS
, когда вы хотите вернуть его. Во время этого блока вы не можете использовать большинство функций API Python, и вы несете ответственность за обеспечение безопасности потоков в C. Самый простой способ сделать это — использовать только локальные переменные, а не читать или записывать какое-либо глобальное состояние.
Если у вас уже есть поток C, работающий без GIL (поток A), то простое сохранение GIL в потоке B не гарантирует, что поток A не будет изменять глобальные переменные C. Чтобы быть в безопасности, вы должны убедиться, что вы никогда не изменяете глобальное состояние без какого-либо механизма блокировки (будь то Python GIL или механизм C) во всех ваших функциях C.
Дополнительное мнение
*
Одно из мест, где GIL может быть выпущен в коде C, — это если код C вызывает что-то, что вызывает выполнение кода Python. Это может быть связано с использованием PyObject_Call
. Менее очевидное место было бы, если бы Py_DECREF
вызвало выполнение деструктора. Вы бы вернули GIL к тому времени, когда ваш код C возобновился, но вы больше не могли гарантировать, что глобальные объекты не изменятся. Это очевидное не влияет на простой C, такой как x++
.
Запоздалое редактирование:
Следует подчеркнуть, что очень, очень, очень легко вызвать выполнение кода Python. По этой причине вы не должны использовать GIL вместо мьютекса или фактического механизма блокировки. Вы должны рассматривать его только для операций, которые действительно являются атомарными (т. е. один вызов API C) или полностью для объектов C, отличных от Python. Вы не потеряете GIL неожиданно при выполнении C-кода, но многие вызовы C API могут освободить GIL, сделать что-то еще, а затем восстановить GIL, прежде чем вернуться к вашему C-коду.
Цель GIL — убедиться, что внутренние компоненты Python не повреждены. GIL будет продолжать служить этой цели в модуле расширения. Однако условия гонки, включающие действительные объекты Python, расположенные неожиданным для вас образом, по-прежнему доступны для вас. Например:
PySequence_SetItem(some_list, 0, some_item);
PyObject* item = PySequence_GetItem(some_list, 0);
assert(item == some_item); // may not be true
// the destructor of the previous contents of item 0 may have released the GIL
person
DavidW
schedule
03.02.2017
i++
в C должен быть в порядке; GIL не может быть выпущен посреди этого. Код C не освободит GIL, если он не сделает явный вызов, чтобы дать другим потокам возможность запускаться (но будьте осторожны с вызовами кода, который вы не контролируете, который может сделать этот вызов для вас). - person user2357112 supports Monica   schedule 02.02.2017sleep
или какую-нибудь инструкцию ожидания/ввода? Как только вы вводите код C, это всего лишь одно атомарное выполнение? - person DenverCoder9   schedule 03.02.2017BINARY_ADD
или любой другой код операции может преобразовать в произвольную определяемую пользователем функцию, написанную на Python. Вы должны быть уверены, что выполнение кода операции не может привести к вызову другого кода Python и что любой задействованный код C не приведет к явному освобождению GIL. - person user2357112 supports Monica   schedule 03.02.2017