[英]Python asyncio wait_for synchronous
使用 Python 3.6.8
async def sleeper():
time.sleep(2)
async def asyncio_sleeper():
await asyncio.sleep(2)
await asyncio.wait_for(sleeper(), 1)
await asyncio.wait_for(asyncio_sleeper(), 1)
使用 time.sleep 不会超时,asyncio.sleep 会超时。
我的直觉是,在协程上调用 wait_for 将基于协程需要多长时间,而不是基于协程中的各个异步调用。 导致这种行为的幕后发生了什么,有没有办法修改行为以符合我的直觉?
导致这种行为的幕后发生了什么
最简单的答案是 asyncio 是基于协作多任务的, time.sleep
不协作。 time.sleep(2)
阻塞线程两秒钟,事件循环和所有,任何人都无能为力。
另一方面, asyncio.sleep
是经过精心编写的,因此当您await asyncio.sleep(2)
时,它会立即暂停当前任务并安排事件循环在 2 秒后恢复它。 Asyncio 的“休眠”是隐式的,它允许事件循环在协程挂起时继续执行其他任务。 相同的挂起系统允许wait_for
取消任务,事件循环通过在这样的await
中“恢复”它来完成该任务,以至于它被挂起的等待引发异常。
一般来说,一个不等待任何东西的协程很好地表明它被错误地编写并且只是名义上的协程。 等待是协程存在的原因,而sleeper
不包含任何协程。
有没有办法修改行为以符合我的直觉?
如果您必须从 asyncio 调用遗留阻塞代码,请使用run_in_executor
。 当你这样做时,你必须告诉 asyncio 并允许它执行实际的阻塞调用,如下所示:
async def sleeper():
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, time.sleep, 2)
time.sleep
(或其他阻塞函数)将被移交给一个单独的线程,并且sleeper
将被挂起,待time.sleep
完成后恢复。 与asyncio.sleep()
不同,阻塞 time.sleep time.sleep(2)
仍将被调用并阻塞其线程 2 秒,但这不会影响事件循环,这将 go 关于它的业务类似于它在await asyncio.sleep()
时所做的事情使用await asyncio.sleep()
。
请注意,取消等待run_in_executor
的协程只会取消等待阻塞time.sleep(2)
在另一个线程中完成。 阻塞调用将继续执行直到完成,这是意料之中的,因为没有通用的机制来中断它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.