В чем разница между многопоточностью и асинхронностью в Python

Ответ

Основное различие заключается в модели параллелизма: многопоточность использует вытесняющую многозадачность, а асинхронность — кооперативную.

Многопоточность (Multithreading)

  • Как работает: Несколько потоков выполняются в рамках одного процесса. Операционная система сама переключает контекст между потоками. В CPython из-за GIL (Global Interpreter Lock) реального параллельного выполнения Python-кода на нескольких ядрах CPU не происходит.
  • Когда использовать: Для задач, связанных с ожиданием ввода-вывода (I/O-bound), где потоки могут простаивать в ожидании данных (например, сетевые запросы), или для выноса тяжелых вычислений в C-расширения, которые могут освобождать GIL.
  • Недостатки: Накладные расходы на создание и переключение потоков, сложность синхронизации данных (race conditions, deadlocks).
# Пример: выполнение задач в разных потоках
import threading
import time

def slow_task(name):
    print(f"Поток {name}: начинаю задачу")
    time.sleep(2)
    print(f"Поток {name}: завершаю задачу")

thread1 = threading.Thread(target=slow_task, args=("A",))
thread2 = threading.Thread(target=slow_task, args=("B",))

thread1.start()
thread2.start()

thread1.join()
thread2.join()
# Оба потока стартуют почти одновременно и выполняются "параллельно"

Асинхронность (Asynchrony / asyncio)

  • Как работает: Весь код выполняется в одном потоке. Переключение между задачами (корутинами) происходит явно в коде с помощью ключевого слова await, когда задача ожидает завершения I/O операции. Управляется циклом событий (event loop).
  • Когда использовать: Идеально для большого количества одновременных I/O-bound задач (веб-серверы, парсеры, боты), так как потребляет значительно меньше ресурсов по сравнению с потоками.
  • Недостатки: Не подходит для CPU-bound задач, так как одна долгая синхронная операция заблокирует весь поток и цикл событий.
# Пример: асинхронное выполнение
import asyncio

async def slow_task(name):
    print(f"Задача {name}: начинаю")
    await asyncio.sleep(2)
    print(f"Задача {name}: завершаю")

async def main():
    # Задачи создаются и запускаются конкурентно
    await asyncio.gather(
        slow_task("A"),
        slow_task("B")
    )

asyncio.run(main())