我有一个以特定频率触发事件的函数,以及一个作为动作的协程任务。下面是我的实现(功能
wrapper
),但是它们似乎同时运行,发生了什么事?
import time
import asyncio
start = time.time()
def main(callback):
for i in range(5):
time.sleep(.5)
callback()
async def sub_task():
print("sub_task", time.time() - start)
#-----------------------
# below is what i do
def wrapper():
asyncio.create_task(sub_task())
main(wrapper)
# output: why don't they run at 0.5 sec interval?
#sub_task 2.57704758644104
#sub_task 2.57704758644104
#sub_task 2.57704758644104
#sub_task 2.5780487060546875
#sub_task 2.5780487060546875
您的代码有几处错误,很难解释所有这些,因此,我将向您展示执行您期望的代码,然后进行解释:
import time
import asyncio
from typing import Coroutine, Callable
START = time.time()
async def run_loop(callback: Callable[[], Coroutine]) -> None:
for _ in range(5):
await asyncio.sleep(0.5)
await callback()
async def sub_task() -> None:
print("sub_task", time.time() - START)
async def main() -> None:
await run_loop(sub_task)
asyncio.run(main())
sub_task 0.5007944107055664
sub_task 1.0015990734100342
sub_task 1.5024292469024658
sub_task 2.003257989883423
sub_task 2.504088878631592
那么,这是如何运作的? 首先,我相信您知道您确实需要与当前配置异步运行所有这些。我假设 async-nes 出现在示例中未显示的部分中。 编辑:正如 Michael Butscher 指出的那样,这也解释了为什么您当前的代码会同时运行:在笔记本中,当您没有正在运行的事件循环并尝试添加它时,循环将最后运行,在阻塞代码完成。在我测试它的终端中,它根本不会运行。
那么,您没有在当前代码中运行异步循环。我认为这也只是因为您忘记将它添加到示例中。在这种情况下,我使用
asyncio.run
来启动循环并确保我们在示例的其余部分处于异步函数中。重要的是要注意run_loop
也需要是一个异步函数:否则,它需要在每次要运行时创建自己的异步循环,阻塞其他一切。我想你还有其他异步的事情要做,所以,这个也需要是异步的。
然后,有几点需要注意: 首先,
time.sleep
块一切, 也是异步代码。如果你不想让 sleep 阻塞当前异步函数之外的东西,你应该使用 await asyncio.sleep()
然后,在您的
create_task
中调用函数 sub_task
这将返回一个未来。你忘记的是,未来只能等待一次。如果你想多次等待一个async
函数,你需要多次调用它。我试图通过类型注释使这一点更清楚。
我希望一切都解决了。 :-)