Сколько стоит выпуск GIL?

Предположим, у меня есть функция расширения C, которая делает что-то полностью независимое от интерпретатора Python. Есть ли причина не выпускать GIL?

Например, есть ли причина не писать такой код (кроме таких вопросов, как читабельность и отказ от микрооптимизации - вещи, которые важны, но не имеют отношения к моему вопросу)?

Py_BEGIN_ALLOW_THREADS
    a = 1 + 1;
Py_END_ALLOW_THREADS

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

4 ответа

Решение

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

Итак, обычно это не очень хорошая идея:

Py_BEGIN_ALLOW_THREADS
    a = 1 + 1;
Py_END_ALLOW_THREADS

Здесь происходит разблокировка мьютекса, который вы пытаетесь снова заблокировать сразу же после этого. Если это разрыв между двумя большими кусками кода, то это дает возможность другому потоку работать. Но если у вас нет проблем с гранулярностью потоков, просто сохраните блокировку.

Так что это хорошая идея в этом контексте:

very_long_computation_requires_gil();
Py_BEGIN_ALLOW_THREADS;
a = a + i;
Py_END_ALLOW_THREADS;
very_long_computation_also_requires_gil();

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

Если у вас есть функция расширения C, которая делает что-то полностью независимое от интерпретатора Python, то выпуск GIL обычно является хорошей идеей. Единственным недостатком является ожидание, чтобы вернуть GIL. В Python 3.2 вы должны ждать минимум 1/20 секунды.

Эксперты все еще работают над тестированием GIL.

Это новые идеи о старой проблеме: http://dabeaz.blogspot.com/2011/08/inside-look-at-gil-removal-patch-of.html

Вы также можете попробовать использовать Stackless Python (без GIL) или PyPy ( Python с компилятором Just-In-Time).

Есть ли причина не выпускать GIL?

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

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

Другой основной причиной освобождения GIL является вызов C-расширения, которое блокирует (например, блокирует чтение в сокете), чтобы позволить другим потокам работать. Это именно то, что происходит, когда интерпретатор Python сам выполняет блокирующую операцию в потоке.

Другие вопросы по тегам