← Назад к вопросам

В чем разница между вытесняющей и конкурентной многозадачность?

3.0 Senior🔥 101 комментариев
#Python Core#Асинхронность и многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Вытесняющая vs Конкурентная многозадачность

Это два способа организации выполнения нескольких задач "одновременно", но они работают принципиально по-разному.

Конкурентная многозадачность (Cooperative multitasking)

Задачи сами передают управление друг другу в нужные моменты.

import asyncio

async def task1():
    print("Task 1: начало")
    await asyncio.sleep(1)  # Явно передаём управление
    print("Task 1: конец")

async def task2():
    print("Task 2: начало")
    await asyncio.sleep(0.5)
    print("Task 2: конец")

async def main():
    await asyncio.gather(task1(), task2())

# Результат:
# Task 1: начало
# Task 2: начало
# Task 2: конец
# Task 1: конец

Здесь task1 говорит: "я жду 1 секунду, пока я жду, выполняй task2". После этого передача управления происходит явно через await.

Вытесняющая многозадачность (Preemptive multitasking)

Операционная система сама решает, какой процесс/поток выполнять в каждый момент времени. Может прервать в любой точке.

import threading
import time

def task1():
    print("Task 1: начало")
    time.sleep(1)
    print("Task 1: конец")

def task2():
    print("Task 2: начало")
    time.sleep(0.5)
    print("Task 2: конец")

# Создаём потоки
t1 = threading.Thread(target=task1)
t2 = threading.Thread(target=task2)

t1.start()
t2.start()
t1.join()
t2.join()

# Результат может быть:
# Task 1: начало
# Task 2: начало
# Task 2: конец
# Task 1: конец

ОС сама решает, когда дать процессорное время каждому потоку. Это может произойти в любой момент.

Ключевые различия

АспектКонкурентнаяВытесняющая
Передача управленияЯвная (await, yield)Автоматическая (ОС)
ПредсказуемостьВысокая (контролируем)Низкая (может прервать)
СинхронизацияПроще (no race conditions)Сложнее (нужны Lock, Semaphore)
Потребление ресурсовДешевлеДороже
Масштабируемость10000+ задачОбычно 100-1000 потоков
Context switchЯвный (когда await)Частый (каждые ms)

В Python

Конкурентная — asyncio:

import asyncio

async def fetch_data(url):
    print(f"Fetching {url}")
    await asyncio.sleep(1)  # Имитация I/O
    return f"Data from {url}"

async def main():
    # Все запросы выполнятся "одновременно"
    results = await asyncio.gather(
        fetch_data("/api/users"),
        fetch_data("/api/posts"),
        fetch_data("/api/comments")
    )
    return results

asyncio.run(main())

Этот код выполнится примерно за 1 секунду, потому что все три fetch_data будут чередоваться.

Вытесняющая — threading:

import threading
from concurrent.futures import ThreadPoolExecutor

def fetch_data(url):
    import time
    print(f"Fetching {url}")
    time.sleep(1)
    return f"Data from {url}"

with ThreadPoolExecutor(max_workers=3) as executor:
    results = list(executor.map(fetch_data, [
        "/api/users",
        "/api/posts",
        "/api/comments"
    ]))

Тоже выполнится за ~1 секунду, но ОС управляет потоками.

Проблемы

Конкурентная (asyncio):

  • Если забыть await, код выполнится синхронно
  • Блокирующие операции остановят весь event loop
# НЕПРАВИЛЬНО - весь loop замерзнет
async def bad():
    time.sleep(10)  # Блокирующая операция!
    await asyncio.sleep(1)

# ПРАВИЛЬНО
async def good():
    await asyncio.sleep(10)  # Неблокирующая

Вытесняющая (threading):

  • Race conditions (два потока изменяют одну переменную)
  • Deadlocks
  • Нужны Lock для синхронизации
import threading

counter = 0
lock = threading.Lock()

def increment():
    global counter
    with lock:  # Защищаем критическую секцию
        counter += 1

threads = [threading.Thread(target=increment) for _ in range(100)]
for t in threads:
    t.start()
for t in threads:
    t.join()

print(counter)  # Точно 100

Когда использовать

Asyncio (конкурентная):

  • I/O-bound операции (HTTP запросы, БД запросы)
  • Нужно обработать много соединений
  • Простота синхронизации

Threading (вытесняющая):

  • CPU-bound операции
  • Когда нужны настоящие параллельные вычисления
  • Интеграция с блокирующими библиотеками

Вывод: в Python asyncio предпочтительнее для web-приложений, т.к. большинство операций — I/O.