Асинхронный сон Python — занимает слишком много времени

У меня есть асинхронное приложение, которое я запускаю, и оно очень чувствительно ко времени, поэтому я пытаюсь проработать и убрать любой блокирующий код, который я могу найти.

Я использую asyncio.run() с отладкой = True.

Как вы можете видеть, селектор ввода-вывода блокируется на 0,852 секунды при выходе из спящего режима, согласно документации Python:

The execution time of the I/O selector is logged if it takes too long to perform an I/O operation.
20/04/23 12:04:20 WARNING  asyncio: Executing <Task pending name='Task-99' coro=<CodeRunner.run_forever() running at /code/testcode.py:929> wait_for=<Future pending cb=[Task.task_wakeup()]        base_events.py:1917
                           created at /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py:427> cb=[_run_until_complete_cb() at
                           /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py:180] created at
                           /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py:100> took 0.852 seconds

Рассматриваемый код:

        while True:
            if counter % CONTACT_SCHEDULE == 0:
                await self.run_once()
                counter = 0
                log.info(f"Sleeping {CONTACT_SCHEDULE} seconds...")

            progress.refresh()

            counter += 1
            await asyncio.sleep(1)  <--- this is line 929

Мой вопрос: почему asyncio.sleep(1) вызывает зависание моего кода? Это потому, что что-то еще работает в то же время и блокирует?

Это не слишком длинное сообщение селектора ввода/вывода. Это медленное сообщение обратного вызова — обратный вызов, запланированный с помощью чего-то вроде loop.call_soon или loop.call_soon_threadsafe, занял больше 100 миллисекунд.

user2357112 20.04.2023 03:14
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
64
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я думаю, что ваш вызов asyncio.sleep(1) использует здесь цикл событий по умолчанию, который создает проблему, с которой вы столкнулись.

Вместо этого передайте свой цикл событий в качестве параметра в качестве параметра asyncio

await asyncio.sleep(1, loop=referenceToYourEventLoop)

Параметр loop был удален в версии 3.10.

user2357112 20.04.2023 03:19
Ответ принят как подходящий

Это не сообщение о медленном селекторе ввода-вывода, и оно не говорит о том, что asyncio.sleep является проблемой. Это медленное сообщение обратного вызова, описание которого вы увидите в следующем пункте маркированного списка в режиме отладки asyncio docs после части, которую вы процитировали:

  • Обратные вызовы, занимающие более 100 мс, регистрируются. Атрибут loop.slow_callback_duration можно использовать для установки минимальной продолжительности выполнения в секундах, которая считается «медленной».

Судя по деталям сообщения, это похоже на внутренний обратный вызов, используемый для Task.__step, который запускает сопрограмму, в которую заворачивается задача, до тех пор, пока сопрограмма не приостановится.

asyncio.sleep это не проблема. Это как раз то место, где ваша сопрограмма приостановилась. Предупреждающее сообщение пытается сообщить вам, что ваша сопрограмма работала непрерывно в течение 0,852 секунды между тем, когда она проснулась, и тем, когда она была приостановлена ​​​​на asyncio.sleep.

Мы не можем сказать, почему ваша сопрограмма заняла так много времени. Похоже, что-то очень медленное и синхронное произошло в self.run_once или progress.refresh, но у нас недостаточно информации, чтобы что-то сказать о том, что это было.

Большое спасибо @user2357112 - ценю понимание

David White 20.04.2023 03:50

Другие вопросы по теме