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

Можно ли выполнить параллельно 10 запросов, если каждый занимает 20 секунд?

1.8 Middle🔥 161 комментариев
#Асинхронность и многопоточность

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

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

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

Можно ли выполнить параллельно 10 запросов, если каждый занимает 20 секунд?

Прямой ответ: ДА, МОЖНО

Да, 10 запросов можно выполнить параллельно. Время выполнения будет примерно 20 секунд (время одного запроса), а не 200 секунд (сумма всех). Это основное преимущество асинхронного программирования и параллелизма.

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

Последовательное выполнение (синхронное):

Запрос 1: [========] 20s
Запрос 2:          [========] 20s
Запрос 3:                  [========] 20s
...
Запрос 10:                            [========] 20s

Общее время: 200 секунд

Параллельное выполнение (асинхронное/многопоточное):

Запрос 1: [========]
Запрос 2: [========]
Запрос 3: [========]
...
Запрос 10:[========]

Общее время: 20 секунд (+ небольшие затраты на управление)

Способ 1: Asyncio (рекомендуется для I/O задач)

import asyncio
import aiohttp
import time

async def fetch_data(session, url, request_number):
    """Асинхронный запрос"""
    print(f"[{request_number}] Начало запроса")
    async with session.get(url) as response:
        # Ждём ответ (20 сек)
        data = await response.json()
        print(f"[{request_number}] Готово ({len(data)} байт)")
        return data

async def main():
    urls = [f"https://api.example.com/data/{i}" for i in range(10)]
    
    async with aiohttp.ClientSession() as session:
        # Запустить все 10 запросов параллельно
        tasks = [
            fetch_data(session, url, i)
            for i, url in enumerate(urls)
        ]
        results = await asyncio.gather(*tasks)
    
    return results

if __name__ == '__main__':
    start = time.time()
    results = asyncio.run(main())
    elapsed = time.time() - start
    
    print(f"\nВремя выполнения: {elapsed:.1f} сек")
    # Результат: ~20 сек (не 200!)

Способ 2: Многопоточность (Threading)

import threading
import requests
import time
from concurrent.futures import ThreadPoolExecutor

def fetch_data(url, request_number):
    """Синхронный запрос в отдельном потоке"""
    print(f"[{request_number}] Начало")
    response = requests.get(url, timeout=20)  # 20 сек ожидания
    print(f"[{request_number}] Готово")
    return response.json()

def main():
    urls = [f"https://api.example.com/data/{i}" for i in range(10)]
    
    # ThreadPoolExecutor автоматически управляет потоками
    with ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(
            lambda item: fetch_data(item[1], item[0]),
            enumerate(urls)
        ))
    
    return results

if __name__ == '__main__':
    start = time.time()
    results = main()
    elapsed = time.time() - start
    
    print(f"\nВремя выполнения: {elapsed:.1f} сек")
    # Результат: ~20 сек

Способ 3: Multiprocessing (для CPU-bound операций)

from multiprocessing import Pool
import time

def process_request(args):
    """Обработка в отдельном процессе"""
    request_number, data_size = args
    
    # Имитация запроса
    time.sleep(20)
    
    # Вычисление (CPU-bound)
    result = sum(range(10_000_000))
    
    print(f"[{request_number}] Готово: {result}")
    return result

if __name__ == '__main__':
    start = time.time()
    
    with Pool(processes=10) as pool:
        # Запустить 10 процессов параллельно
        results = pool.map(
            process_request,
            [(i, 1000) for i in range(10)]
        )
    
    elapsed = time.time() - start
    print(f"\nВремя выполнения: {elapsed:.1f} сек")
    # Результат: ~20 сек на многоядерной системе

Важный момент: Asyncio vs Threading vs Multiprocessing

ПодходДля I/OДля CPUНакладные расходыРекомендация
AsyncioОтличноеПлохоеНизкиеI/O операции
ThreadingХорошееПлохое (GIL)СредниеI/O в Python
MultiprocessingХорошееОтличноеВысокиеCPU операции

Практический пример: параллельные API запросы

import asyncio
import aiohttp
from typing import List

class DataFetcher:
    def __init__(self, max_concurrent=10):
        self.max_concurrent = max_concurrent
    
    async def fetch_all(self, urls: List[str]):
        """Загрузить все URLs параллельно"""
        connector = aiohttp.TCPConnector(limit=self.max_concurrent)
        timeout = aiohttp.ClientTimeout(total=20)
        
        async with aiohttp.ClientSession(
            connector=connector,
            timeout=timeout
        ) as session:
            tasks = [
                self._fetch_one(session, url)
                for url in urls
            ]
            return await asyncio.gather(*tasks, return_exceptions=True)
    
    async def _fetch_one(self, session, url):
        try:
            async with session.get(url) as response:
                return await response.json()
        except asyncio.TimeoutError:
            return {'error': 'timeout'}
        except Exception as e:
            return {'error': str(e)}

# Использование
async def main():
    fetcher = DataFetcher(max_concurrent=10)
    urls = [f"https://api.example.com/user/{i}" for i in range(10)]
    
    results = await fetcher.fetch_all(urls)
    print(f"Загружено {len(results)} результатов")
    return results

if __name__ == '__main__':
    asyncio.run(main())

Почему это работает?

  1. I/O Wait - пока происходит сетевой запрос (20 сек), процесс не использует CPU
  2. Контекстные переключения - ОС может переключать между потоками/процессами
  3. Асинхронность - код может ждать несколько операций одновременно
# Визуально:
# Время: 0s -----> 10s -----> 20s
# Поток 1: [ждёт ответа от сервера...] готово
# Поток 2:        [ждёт ответа...] готово
# Поток 3:               [ждёт...] готово
#
# В каждый момент процессор может обработать другие операции

Ограничения в реальной жизни

# На практике время будет немного больше 20 сек:
# - Сетевые задержки
# - Сетевые пакеты
# - Переключение контекста
# - Управление памятью

# Более реальный результат: ~20-25 сек

Вывод

ДА, 10 запросов по 20 секунд каждый можно выполнить за ~20 секунд используя:

  • Asyncio - лучший выбор для чистых I/O операций
  • Threading - когда нужна совместимость и простота
  • Multiprocessing - когда есть CPU-intensive операции

Этот принцип параллелизма - одно из самых мощных улучшений производительности в современном программировании.

Можно ли выполнить параллельно 10 запросов, если каждый занимает 20 секунд? | PrepBro