Ответ
Основное различие заключается в модели параллелизма: многопоточность использует вытесняющую многозадачность, а асинхронность — кооперативную.
Многопоточность (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())