Примечание: где бы я ни упоминал, threadя имею в виду именно потоки в Python, пока явно не указано иное.
В 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()
Если поток выполняет некоторые операции, связанные с вводом-выводом (доступ к файловой системе Ex или
сетевой ввод-вывод)
GIL освобождается всякий раз, когда поток ожидает завершения некоторой операции ввода-вывода.
Which thread to switch to next?
У интерпретатора нет собственного планировщика. Какой поток становится запланированным в конце интервала, решает операционная система. .