Python asyncio sleep – taking excessive time.

huangapple go评论70阅读模式
英文:

Python asyncio sleep - taking excessive time

问题

以下是翻译好的部分:

我有一个 asyncio 应用程序正在运行,对时间要求相当敏感 - 因此,我正在尝试处理和清理所有可能的阻塞代码。

我正在使用 asyncio.run(),并且启用了 debug=True。

正如你所看到的,I/O 选择器在从休眠中唤醒时被阻塞了 0.852 秒,根据 Python 文档:

如果执行 I/O 操作需要太长时间,将记录 I/O 选择器的执行时间。
20/04/23 12:04:20 警告  asyncio:执行 <任务待定名称='Task-99' 协程=<CodeRunner.run_forever() 正在运行于 /code/testcode.py:929> wait_for=<Future 待定回调=[Task.task_wakeup()]        base_events.py:1917
                           创建于 /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py:427> 回调=[_run_until_complete_cb()                           /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py:180] 创建于
                           /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py:100> 花费了 0.852 秒

相关代码:

        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)  <--- 这是第 929

我的问题是,为什么 asyncio.sleep(1) 会导致我的代码挂起?是因为同时运行了其他代码并且阻塞了吗?

英文:

I have an asyncio app that I'm running that is quite time sensitive - so I'm trying to work through and tidy up any blocking code I can find.

I am using asyncio.run() with debug=True.

As you can see the I/O selector is blocked for 0.852 seconds waking up from sleep, as per the Python docs:

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

The code in question:

        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

My question is, why is asyncio.sleep(1) causing my code to hang? Is it because something else is running at the same time and blocking?

答案1

得分: 3

这不是一个慢I/O选择器消息,也不是在说asyncio.sleep是问题所在。这是一个慢回调消息,你会在asyncio调试模式文档的下一个项目中看到描述,你引用的部分之后:

  • 持续时间超过100毫秒的回调将被记录。可以使用loop.slow_callback_duration属性来设置被视为“慢”的最小执行持续时间(以秒为单位)。

根据消息的详细信息,它似乎是用于Task.__step的内部回调,该回调运行协程,直到协程暂停。

asyncio.sleep不是问题所在。它只是你的协程恰好在哪里暂停的地方。警告消息试图告诉你,你的协程在唤醒和暂停asyncio.sleep之间连续运行了0.852秒。

我们无法告诉你为什么你的协程需要那么长时间。听起来self.run_onceprogress.refresh中发生了非常慢和同步的事情,但我们没有足够的信息来说明那是什么。

英文:

That's not a slow I/O selector message, and it's not saying that asyncio.sleep is the problem. That's a slow callback message, which you'll see described in the next bullet point in the asyncio debug mode docs after the part you quoted:

> * Callbacks taking longer than 100ms are logged. The loop.slow_callback_duration attribute can be used to set the minimum execution duration in seconds that is considered “slow”.

Judging by the details of the message, it looks like an internal callback used for Task.__step, which runs the coroutine a task is wrapping until the coroutine suspends.

asyncio.sleep isn't the problem. It's just where your coroutine happened to suspend. The warning message is trying to tell you that your coroutine ran continuously for 0.852 seconds between when it woke up and when it suspended for asyncio.sleep.

We can't tell why your coroutine took that long. It sounds like something very slow and synchronous happened in self.run_once or progress.refresh, but we don't have enough info to say anything about what that was.

答案2

得分: -1

我认为你调用 asyncio.sleep(1) 使用了默认的事件循环,这导致了你面临的问题。

相反,将你的事件循环作为参数传递给 asyncio:

await asyncio.sleep(1, loop=referenceToYourEventLoop)
英文:

I think your call to asyncio.sleep(1) uses the default event loop here which creates the problem you're facing.

Instead, pass your event loop as a parameter as a parameter to asyncio

await asyncio.sleep(1, loop=referenceToYourEventLoop)

huangapple
  • 本文由 发表于 2023年4月20日 08:11:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76059665.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定