Вопрос проверяет понимание ограничений asyncio.gather при массовом запуске корутин и рисков перегрузки системы.
asyncio.gather — это удобный инструмент для параллельного выполнения нескольких корутин. Однако он не предоставляет встроенных механизмов ограничения параллелизма. Если передать в gather список из сотен или тысяч корутин, все они будут запущены практически одновременно. Это может привести к нескольким проблемам.
import asyncio
import aiohttp
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = ["http://example.com"] * 10000 # 10 000 одинаковых URL
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks) # Запускает все сразу
В этом примере 10 000 корутин попытаются одновременно открыть соединения к example.com. Это может привести к ошибкам соединения или падению клиента.
Для контроля параллелизма используйте asyncio.Semaphore или библиотеки-обёртки:
import asyncio
semaphore = asyncio.Semaphore(100) # Ограничиваем до 100 одновременных задач
async def limited_fetch(session, url):
async with semaphore:
async with session.get(url) as response:
return await response.text()
async def main():
urls = ["http://example.com"] * 10000
async with aiohttp.ClientSession() as session:
tasks = [limited_fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
Также можно использовать asyncio.wait с параметром return_when=FIRST_COMPLETED и обрабатывать результаты по мере завершения, но gather с семафором — самый простой и надёжный способ.
asyncio.gather подходит для небольших групп корутин, но при массовом запуске всегда используйте ограничение параллелизма. Это защитит и вашу систему, и внешние сервисы от перегрузки.