DEBUG и INFO.  Включайте ID тасков для сопоставления событий.asyncio.get_running_loop().set_debug(True) для выявления медленных корутин и не освобожденных ресурсов.  Также полезен asyncio.Task.all_tasks() для мониторинга активных задач.pdb) или отладчик IDE (например, PyCharm) с поддержкой асинхронности.  Может потребоваться настройка для корректной отладки корутин.cProfile или py-spy, чтобы выявить узкие места в производительности.  Анализируйте, какие корутины тратят больше всего времени.asyncio-timeline, для отображения времени выполнения корутин и выявления блокировок.asyncio.wait_for) чтобы предотвратить зависания.pytest-asyncio.run_in_executor для запуска блокирующего кода в отдельном потоке.Отладка асинхронного кода на Python требует особого подхода, поскольку стандартные инструменты отладки могут не всегда корректно отображать последовательность событий и взаимосвязи между корутинами. Вот несколько стратегий и инструментов, которые помогут отладить асинхронный код, чтобы избежать блокировок и проблем с производительностью:
asyncio.run(debug=True):
            Это, пожалуй, самый простой способ начать отладку.  Включите режим отладки asyncio, установив параметр debug=True при запуске вашего event loop с помощью asyncio.run(). Это позволит получить более подробную информацию о происходящем, включая сообщения о медленных корутинах, не освобожденных ресурсах и других потенциальных проблемах.
import asyncio
async def main():
    await asyncio.sleep(1)
    print("Done!")
if __name__ == "__main__":
    asyncio.run(main(), debug=True)
    Логгирование - это незаменимый инструмент для отслеживания потока выполнения вашего кода. Вставляйте лог-сообщения в ключевые моменты вашего кода, например, при входе и выходе из корутин, при выполнении операций ввода-вывода и т.д. Используйте различные уровни логгирования (DEBUG, INFO, WARNING, ERROR) для фильтрации сообщений и фокусировки на наиболее важных. Пример:
import asyncio
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
async def my_coroutine(i):
    logger.debug(f"Coroutine {i}: starting")
    await asyncio.sleep(0.5)
    logger.debug(f"Coroutine {i}: finishing")
    return i
async def main():
    tasks = [asyncio.create_task(my_coroutine(i)) for i in range(3)]
    results = await asyncio.gather(*tasks)
    logger.info(f"Results: {results}")
if __name__ == "__main__":
    asyncio.run(main())
    Профилировщики помогают выявить узкие места в вашем коде, показывая, какие функции занимают больше всего времени.  Рассмотрите использование встроенного модуля cProfile или сторонних инструментов, таких как py-spy или scalene.  Они могут помочь определить, какие корутины выполняются слишком долго или блокируют event loop.
import asyncio
import cProfile
import pstats
async def my_coroutine():
    await asyncio.sleep(1)
async def main():
    for _ in range(10):
        await my_coroutine()
if __name__ == "__main__":
    with cProfile.Profile() as pr:
        asyncio.run(main())
    stats = pstats.Stats(pr)
    stats.sort_stats(pstats.SortKey.TIME)
    stats.print_stats(10) # Display the top 10 functions by time
    asyncio.create_task() и мониторинг задач:
            Создавайте задачи с помощью asyncio.create_task() и отслеживайте их состояние (выполнена, отменена, выбросила исключение).  Это позволяет контролировать ход выполнения каждой корутины и быстро выявлять проблемы.  Для отслеживания задач можно использовать asyncio.gather(), asyncio.wait() или самостоятельно вести список задач.
import asyncio
async def my_coroutine(i):
    try:
        await asyncio.sleep(i)
        print(f"Coroutine {i} completed")
        return i
    except asyncio.CancelledError:
        print(f"Coroutine {i} cancelled")
        return None
async def main():
    tasks = [asyncio.create_task(my_coroutine(i)) for i in range(3)]
    # Cancel the first task after 1.5 seconds
    await asyncio.sleep(1.5)
    tasks[0].cancel()
    results = await asyncio.gather(*tasks, return_exceptions=True)
    print(f"Results: {results}")
if __name__ == "__main__":
    asyncio.run(main())
    Некоторые IDE (например, PyCharm, VS Code с расширением Python) предлагают встроенную поддержку asyncio, включая возможность отладки асинхронного кода, визуализацию event loop и т.д. Эти инструменты могут значительно упростить процесс отладки.
Существуют сторонние библиотеки, специально разработанные для отладки asyncio-кода, например, asyncio-debug. Они могут предоставлять более детальную информацию о состоянии event loop, задачах и других аспектах asyncio.
Лучший способ избежать проблем с отладкой - это тщательно спроектировать ваш асинхронный код и проводить его тщательное тестирование. Разбивайте сложные задачи на более мелкие, легко тестируемые корутины. Используйте юнит-тесты для проверки правильности работы каждой корутины и интеграционные тесты для проверки взаимодействия между ними.
Основные причины блокировок в асинхронном коде: выполнение синхронных операций в event loop. Убедитесь, что все операции ввода-вывода выполняются асинхронно.  Используйте asyncio.to_thread() для переноса CPU-bound задач в отдельный поток, чтобы не блокировать event loop.
import asyncio
import time
def blocking_io():
    # Placeholder for a function that performs blocking I/O
    time.sleep(1)
    return "Blocking I/O finished"
async def main():
    loop = asyncio.get_running_loop()
    # Run in a custom thread pool:
    result = await loop.run_in_executor(
        None, blocking_io)  # Use the default thread pool
    print('custom thread pool', result)
if __name__ == "__main__":
    asyncio.run(main())
    Даже если код кажется работающим правильно, регулярно отслеживайте его производительность в реальных условиях. Используйте инструменты мониторинга (например, Prometheus, Grafana) для сбора метрик о времени выполнения корутин, загрузке ЦП, использовании памяти и т.д. Это поможет выявить скрытые проблемы с производительностью.
Помните, что отладка асинхронного кода - это итеративный процесс, требующий терпения и внимательности. Комбинируйте различные методы и инструменты, чтобы получить наиболее полную картину о происходящем в вашем коде.