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

Как затрачивается CPU в асинхронности?

2.3 Middle🔥 141 комментариев
#Python Core

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

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

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

Как затрачивается CPU в асинхронности?

Этот вопрос базируется на критичном непонимании: асинхронность не снижает потребление CPU для CPU-bound операций. Асинхронность эффективна только для I/O-bound операций.

Синхронное выполнение

import time

def fetch_data(url):
    time.sleep(2)  # Имитация сетевого запроса
    return f"Data from {url}"

# Синхронный код
start = time.time()
result1 = fetch_data("api1.com")
result2 = fetch_data("api2.com")
result3 = fetch_data("api3.com")
print(f"Total time: {time.time() - start}s")
# Total time: 6.0s (2 + 2 + 2)

Процесс блокируется на каждый запрос. CPU не занят (ждёт I/O), но поток занят.

Асинхронное выполнение

import asyncio

async def fetch_data(url):
    await asyncio.sleep(2)  # Имитация сетевого запроса
    return f"Data from {url}"

# Асинхронный код
async def main():
    start = time.time()
    result1, result2, result3 = await asyncio.gather(
        fetch_data("api1.com"),
        fetch_data("api2.com"),
        fetch_data("api3.com"),
    )
    print(f"Total time: {time.time() - start}s")
    # Total time: 2.0s (работают параллельно!)

asyncio.run(main())

Замечание: оба варианта затрачивают одинаковое количество CPU! Потребление CPU такое же, но асинхронность работает быстрее, так как не ждёт.

I/O-bound vs CPU-bound

I/O-bound (сетевые запросы, чтение файлов)

# СИНХРОННО
import requests

def sync_requests():
    start = time.time()
    for i in range(3):
        response = requests.get("https://api.github.com")  # Блокирует 1-2 сек
    print(f"Time: {time.time() - start}s")  # ~3 сек

# АСИНХРОННО
import aiohttp
import asyncio

async def async_requests():
    async with aiohttp.ClientSession() as session:
        start = time.time()
        tasks = []
        for i in range(3):
            tasks.append(session.get("https://api.github.com"))  # Не блокирует!
        await asyncio.gather(*tasks)
        print(f"Time: {time.time() - start}s")  # ~1 сек

asyncio.run(async_requests())

Временная шкала:

Синхронно:  [Request 1 ........][Request 2 ........][Request 3 ........] = 3 сек
Асинхронно: [Request 1 ....][Request 2 ....][Request 3 ....] = 1 сек (параллельно)

CPU затрачено: Одинаково! Но асинхронность работает 3x быстрее.

CPU-bound (вычисления, обработка данных)

def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# СИНХРОННО
import time
start = time.time()
for i in range(3):
    result = fibonacci(35)  # Тяжёлое вычисление
print(f"Time: {time.time() - start}s")  # ~3 сек
print(f"CPU usage: 100%")

# АСИНХРОННО
import asyncio

async def async_fibonacci():
    start = time.time()
    tasks = [
        asyncio.create_task(asyncio.to_thread(fibonacci, 35)),
        asyncio.create_task(asyncio.to_thread(fibonacci, 35)),
        asyncio.create_task(asyncio.to_thread(fibonacci, 35)),
    ]
    await asyncio.gather(*tasks)
    print(f"Time: {time.time() - start}s")  # ~3 сек (одинаково!)
    print(f"CPU usage: 100%")

asyncio.run(async_fibonacci())

CPU затрачено: Одинаково! Асинхронность не помогает для CPU-bound операций на одном процессе (одном ядре CPU).

Как затрачивается CPU в асинхронности

Event Loop (главный цикл событий)

Асинхронный код работает в одном потоке через Event Loop:

import asyncio

async def task1():
    print("Task 1 start")  # CPU: 0.1%
    await asyncio.sleep(1)  # CPU: 0% (Event Loop уходит в другую задачу)
    print("Task 1 end")  # CPU: 0.1%

async def task2():
    print("Task 2 start")  # CPU: 0.1%
    await asyncio.sleep(1)  # CPU: 0% (Event Loop уходит в другую задачу)
    print("Task 2 end")  # CPU: 0.1%

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

# Event Loop расписание:
# 1. task1.start() — CPU работает
# 2. task1.await sleep() — CPU отдыхает
# 3. task2.start() — CPU работает
# 4. task2.await sleep() — CPU отдыхает
# 5. task1.end() — CPU работает
# 6. task2.end() — CPU работает
# Всего: 2 сек (параллельно), CPU ~1%

Проблема GIL (Global Interpreter Lock) в Python

Python на одном процессе (one thread):

# GIL позволяет только ОДНОМУ потоку работать с Python объектами одновременно

# НЕПРАВИЛЬНО для CPU-bound — threading не поможет
import threading
import time

def cpu_bound_task():
    total = 0
    for i in range(100_000_000):
        total += i

start = time.time()
threads = [
    threading.Thread(target=cpu_bound_task),
    threading.Thread(target=cpu_bound_task),
]
for t in threads:
    t.start()
for t in threads:
    t.join()
print(f"Time: {time.time() - start}s")  # ~20 сек (медленнее чем синхронно!)

# ПРАВИЛЬНО для CPU-bound — используйте multiprocessing
import multiprocessing

start = time.time()
processes = [
    multiprocessing.Process(target=cpu_bound_task),
    multiprocessing.Process(target=cpu_bound_task),
]
for p in processes:
    p.start()
for p in processes:
    p.join()
print(f"Time: {time.time() - start}s")  # ~10 сек (параллельно, 2 ядра)

Затрачивание CPU в асинхронности

I/O-bound операция

Асинхронно (asyncio):

Event Loop:  [Task1.run] → [await I/O] → [Task2.run] → [await I/O] → [Task1.end]
CPU:         [■■■■]       [          ]  [■■■■]       [          ]  [■■■■]  ~5%
Time:        3 сек (параллельно)

CPU-bound операция

Одного потока (asyncio):

Event Loop:  [Task1.compute] → [Task2.compute] → [Task1.compute]
CPU:         [■■■■■■■■■■■] → [■■■■■■■■■■■] → [■■■■■■■■■■■]  100% одного ядра
Time:        3 сек (последовательно на одном ядре)

Мультипроцесс (multiprocessing):

Core 1:      [Task1.compute ....]
Core 2:      [Task2.compute ....]
CPU:         [■■■■■■■■■■■][■■■■■■■■■■■]  100% обоих ядер
Time:        1.5 сек (параллельно на разных ядрах)

Выводы

  1. Асинхронность НЕ снижает CPU для CPU-bound операций
  2. Асинхронность ЭКОНОМИТ CPU для I/O-bound (освобождает thread/process для других операций)
  3. I/O-bound: Используйте asyncio (async/await)
  4. CPU-bound: Используйте multiprocessing (отдельные процессы, другие ядра)
  5. GIL — проблема Python для threading, не для asyncio

Асинхронность эффективна для I/O-wait, а не для CPU-bound вычисления.