Примечание: везде, где я упоминаю thread
, я имею в виду конкретно потоков в питоне до тех пор, пока не будет указано явно.
Потоки работают немного по-другому в Python, если вы пришли из C/C++
фона. В python только один поток может быть в рабочем состоянии в определенный момент времени. Это означает, что потоки в python не могут по-настоящему использовать возможности нескольких процессорных ядер, так как по своей конструкции потоки не могут работать параллельно на нескольких ядрах.
Поскольку управление памятью в python не является потокобезопасным, каждому потоку требуется эксклюзивный доступ к структурам данных в интерпретаторе python. Этот эксклюзивный доступ обеспечивается механизмом, называемым GIL
(глобальная блокировка интерпретации) .
Why does python use GIL?
Для предотвращения одновременного доступа нескольких потоков к состоянию интерпретатора и повреждения состояния интерпретатора.
Идея состоит в том, что всякий раз, когда выполняется поток (даже если это основной поток) , получается GIL и через некоторый предопределенный интервал времени
GIL освобождается текущим потоком и повторно запрашивается другим потоком (если есть).
Why not simply remove GIL?
Это не так, что невозможно удалить GIL, просто в результате этого мы в конечном итоге устанавливаем множественные блокировки внутри интерпретатора для сериализации доступа, что делает даже одно поточное приложение менее производительным.
, поэтому стоимость удаления GIL компенсируется снижением производительности однопоточного приложения, что никогда не требуется.
So when does thread switching occurs in python?
Переключение нити происходит при отпускании GIL. Так, когда GIL выпущен?
Необходимо принять во внимание два сценария.
Если поток выполняет операции привязки к процессору (например, обработка изображений).
В более старых версиях python переключение потоков происходило после фиксированного количества инструкций python. По умолчанию было установлено значение 100
. Оказалось, что это не очень хорошая политика для принятия решения. когда переключение должно произойти, так как время, затрачиваемое на выполнение одной инструкции, может
очень дико от миллисекунды до даже секунды. Поэтому выпуск GIL после каждых 100
инструкций независимо от времени, которое они требуют для выполнения, является плохой политикой.
В новых версиях вместо использования счетчика команд в качестве метрики для переключения потока используется настраиваемый интервал времени.
Интервал переключения по умолчанию составляет 5 миллисекунд. Вы можете получить текущий интервал переключения, используя sys.getswitchinterval()
.
Это можно изменить с помощью sys.setswitchinterval()
Если поток выполняет некоторые операции ввода-вывода (например, доступ к файловой системе или
)
сетевой ввод / вывод)
GIL освобождается всякий раз, когда поток ожидает некоторого завершения операции ввода-вывода.
Which thread to switch to next?
Интерпретатор не имеет своего собственного планировщика. Какой поток становится запланированным в конце интервала, это решение операционной системы. .