Как работает многопоточность в Python и в чем ее основное ограничение

Ответ

Многопоточность в Python реализована через модуль threading, но ее ключевой особенностью является Global Interpreter Lock (GIL).

GIL — это механизм в стандартном интерпретаторе CPython, который позволяет выполняться только одному потоку с Python-байткодом в один момент времени. Из-за этого потоки не могут по-настоящему параллельно выполняться на нескольких ядрах процессора.

Когда threading эффективен:

  • I/O-bound задачи (ограниченные вводом-выводом): сетевые запросы, работа с файлами, обращение к базам данных. В этих случаях поток отдает GIL, пока ждет ответа, позволяя другим потокам работать.

Когда threading неэффективен:

  • CPU-bound задачи (ограниченные производительностью процессора): сложные математические вычисления, обработка изображений. Здесь GIL не будет освобождаться, и реального ускорения на многоядерной системе не произойдет.

Пример (симуляция I/O-задачи):

import threading
import time

def io_task():
    print(f"Поток {threading.current_thread().name} начал I/O операцию")
    time.sleep(2) # Симуляция ожидания ответа от сети или диска
    print(f"Поток {threading.current_thread().name} завершил операцию")

start_time = time.time()

threads = [
    threading.Thread(target=io_task, name=f"T-{i}") for i in range(3)
]

for t in threads:
    t.start()

for t in threads:
    t.join() # Ожидаем завершения всех потоков

print(f"Все потоки завершились за {time.time() - start_time:.2f} секунд.")
# Вывод: Все потоки завершились за ~2.00 секунд (а не за 6).

Альтернативы для CPU-bound задач:

  • multiprocessing: Создает отдельные процессы со своим GIL, позволяя достичь настоящего параллелизма.
  • asyncio: Для высокоэффективного асинхронного I/O в одном потоке.