Python GIL предотвращает превышение загрузки ЦП на 100% на многоядерной машине?

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

Другими словами, похоже, что GIL фактически переводит многопоточную программу Python в однопоточный режим.

Например:

(1) Поток A получить GIL, выполнить некоторое время, отпустить GIL

(2) Поток B получает GIL, выполняет некоторое время, отпускает GIL

...

Однако после некоторых простых экспериментов я обнаружил, что, хотя GIL снижает производительность, общая загрузка ЦП может превышать 100% на многоядерной машине.

from threading import Thread

def test():
    while 1:
        pass

for i in range(4):
    t = Thread(target=test)
    t.start()

На 4-ядерной 8-поточной машине указанная выше программа будет занимать около 160% использования ЦП. Я что-то неправильно понял? Два потока могут выполняться точно в один и тот же момент? Или в расчете использования ЦП есть ошибка, или что-то не так?

Спасибо


person twds    schedule 29.01.2016    source источник
comment
Как вы измеряете использование ЦП?   -  person Peter Wood    schedule 29.01.2016
comment
Я предполагаю, что Python остается привязанным к одному ядру, но другие процессы могут использовать другое.   -  person msw    schedule 29.01.2016
comment
@PeterWood Если вы запустите top в оболочке, отобразится %CPU.   -  person twds    schedule 30.01.2016
comment
@msw Но если я правильно понимаю, все четыре потока процесса Python должны удерживать GIL перед выполнением.   -  person twds    schedule 30.01.2016


Ответы (2)


По всей вероятности, наблюдаемое вами дополнительное использование ЦП на 60% - это просто борьба различных потоков за GIL.

В конце концов, существует некоторое время, проведенное за пределами GIL, когда интерпретатор работает, чтобы освободить / получить GIL, а планировщик O / S работает над их арбитражем.

person Dolda2000    schedule 02.04.2016

Помимо ответа Dolda2000, байт-код Python будет выполняться только одним процессором за раз из-за GIL. Только определенные модули C (которые не управляют состоянием Python) смогут работать одновременно.

Многопоточность больше подходит для приложений с привязкой к вводу-выводу (ввод-вывод выпускает GIL, что обеспечивает больший параллелизм), в других случаях многопоточность python работает медленнее и демонстрирует пониженную производительность, чем последовательный. Итак, чтобы задействовать все ядра и повысить производительность, используйте многопроцессорность. В этом ответе есть очень хорошее объяснение, проверьте это!

person whoosis    schedule 14.03.2018