Параллелизм: потоки и GIL
Выполняйте пересекающуюся во времени работу потоками, поймите, почему GIL их ограничивает, и держите общее состояние корректным с помощью блокировок
Lock, иначе получите состояние гонки.
- отличать конкурентность от параллелизма,
- запускать и присоединять потоки модулем
threading, - объяснить, что GIL гарантирует и чего он стоит,
- решать, когда потоки помогают (I/O-bound), а когда нет (CPU-bound),
- замечать состояние гонки и чинить его через
Lockилиwith lock:, - использовать
ThreadPoolExecutorиqueue.Queueвместо ручного управления потоками.
1. Конкурентность это не параллелизм
Конкурентность это способ построить программу так, чтобы несколько задач были в процессе одновременно — их можно чередовать на одном ядре, и каждая по очереди продвигается понемногу. Параллелизм это когда задачи буквально выполняются в один и тот же момент на нескольких ядрах. Конкурентность про то, чтобы справляться со многими вещами; параллелизм про то, чтобы делать многое одновременно. Потоки в CPython дают конкурентность; из-за GIL они редко дают параллелизм для чисто питоновской CPU-работы.
Это различие ключ ко всей теме. Потоки позволяют программе ждать много вещей сразу — двадцать открытых сокетов, десять файлов, пять HTTP-запросов — так что общее время по часам сходится к самому долгому одиночному ожиданию, а не к сумме всех. Чего они не могут, так это ускорить один тяжёлый по CPU питоновский цикл.