Первый и самый основной недостаток — это сложность отладки кода. Если в синхронном коде разобраться довольно просто (здесь мы обычно используем принты или библиотеки для логирования), то в асинхронном коде всё не так очевидно.
Второй недостаток плавно вытекает из первого: обработка исключений невозможна вне асинхронных функций. Это можно сделать только внутри event loop, и для этого существует отдельный обработчик loop.set_exception_handler(), который устанавливает новый обработчик исключений.
Третий недостаток — это сложность понимания, какая асинхронная функция выполняется в данный момент. Радует тот факт, что для написания асинхронных парсеров не требуется большое количество функций: как правило, нам необходимо написать от двух до пяти. Но когда вам нужно написать большое количество асинхронных функций, начинаются трудности.
Четвёртый недостаток — сложно читаемый код. Сложность чтения асинхронного кода состоит в том, что все асинхронные функции запускаются через event loop. То есть, мы формируем список задач, который состоит из корутин, после чего передаём его в event loop, где и происходит основная магия. Про то, как устроен event loop, мы будем говорить в следующих разделах курса.
Пятый недостаток заключается в том, что в асинхронных функциях нельзя использовать функции, которые используют CPU-bound операции. В таком случае они будут блокировать выполнение других задач (task) в тот момент, пока идёт вычисление результата для функции. Если коротко, то CPU-bound — это операции, использующие процессор для вычисления, а IO-bound — это операции, использующие ввод/вывод. Именно по этой причине модуль называется asyncio.