Python Gil странное поведение

Посмотрите на этот кусок кода:

from threading import Thread
import time

cpt = 0

def myfunction():
    print("myfunction.start")
    global cpt
    for x in range(10):
        cpt += 1
        time.sleep(0.2)
        print("cpt=%d" % (cpt))
    print("myfunction.end")

thread1 = Thread(target=myfunction)
thread2 = Thread(target=myfunction)
thread1.start()
thread2.start()

Это очень простая функция, которая читает / записывает глобальную переменную. Я запускаю 2 темы на эту же функцию.

Я читал, что Python не очень эффективен с многопоточностью из-за GIL, который автоматически блокирует функции или методы, которые обращаются к тем же ресурсам. Итак, я думал, что Python сначала запустит thread1, а затем thread2, но я вижу в выводе консоли, что 2 потока работают параллельно. Так что я не понимаю, что Гил на самом деле блокирует...

Спасибо

1 ответ

Это из-за sleep системный вызов, который освобождает процессор (и даже "выходит" из интерпретатора на некоторое время)

когда вы делаете time.sleep(0.2)текущий поток приостанавливается системой (а не Python) на определенный промежуток времени, а другой поток может работать.

Обратите внимание, что print заявления или threading.current_thread() то, что вы можете вставить, чтобы шпионить за потоками, также (кратко) уступает системе, так что потоки могут переключаться из-за этого (вспомните кота Шредингера). Настоящий тест будет таким:

from threading import Thread
import time

cpt = 0

def myfunction():
    global cpt
    for x in range(10):
        cpt += 1
        time.sleep(0.2)
    print(cpt)

thread1 = Thread(target=myfunction)
thread2 = Thread(target=myfunction)
thread1.start()
thread2.start()

Здесь вы получаете

20
20

это означает, что каждый поток работал, чтобы увеличить счетчик по очереди.

Теперь прокомментируйте time.sleep() заявление, и вы получите:

10
20

это означает, что первый поток взял на себя все увеличивающиеся, закончил и позволил второму потоку увеличить еще 10 отсчетов. Нет системных вызовов (даже print) убедитесь, что GIL работает в полном объеме.

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

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