asyncio-код на нагрузке часто тормозит из-за того, что стандартный event loop написан на чистом Python. uvloop решает это в лоб: он на Cython, в основе libuv (тот же движок, что у Node.js). По тестам прирост пропускной способности 2x-4x, задержки падают. Но многие разработчики останавливаются на базовой установке, не выжимая максимум.
Базовая настройка и кастомная policy
Установка —
pip install uvloop. Типичная ошибка — просто вызвать asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) и забыть. В production под нагрузкой стоит создать кастомную policy, чтобы сбросить сигнальные хендлеры, которые обычно не нужны, но потребляют память:class MyPolicy(uvloop.EventLoopPolicy):
def new_event_loop(self):
loop = super().new_event_loop()
loop._signal_handlers.clear()
return loop
Это даёт микрооптимизацию без изменения апи. Трейдофф: если ваш код использует сигналы (например, SIGINT), эта политика их потеряет. Использовать только при уверенности, что сигналы не нужны.
Zero-cost cancellation через PEP 654
PEP 654 (Python 3.11+) завёз ExceptionGroup. Раньше при массовой отмене задач ты делал цикл с
task.cancel() и ловил каждый CancelledError. Теперь кидаешь один ExceptionGroup, и это не тянет оверхед на каждую корутину:async def cancel_group(tasks):
if len(tasks) > 5:
raise ExceptionGroup("Cancelling batch",
[asyncio.CancelledError() for _ in tasks])
Прирост особенно заметен на высоких нагрузках, когда отменять приходится десятками и сотнями. Практический совет: используйте ExceptionGroup для батчевых операций, где отмена или ошибка применима к группе задач, а не к каждой по отдельности.
Вывод: uvloop ускоряет asyncio до уровня libuv, а кастомная policy и zero-cost cancellation через PEP 654 убирают узкие места отмены корутин, что критично для high-load production.