使用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基于cooperative多任务,而time.sleep
不合作。 time.sleep(2)
将线程阻塞两秒钟,包括事件循环和所有事件,任何人都无能为力。
另一方面,asyncio.sleep
会被仔细地编写,以便在您等待时立即暂停当前任务,并安排其在超时后恢复。这允许在协程程序睡眠时继续进行事件循环。它也允许通过以特殊方式“恢复”任务以使await
引发异常,从而随时取消任务。
[通常,协程不等待任何东西,可以很好地表明它的书写方式不正确,并且仅是名称上的协程。等待是协程存在的原因,sleeper
不包含。
有没有办法改变行为以符合我的直觉?
如果绝对必须从asyncio调用旧版阻止代码,请使用
run_in_executor
。您仍然必须在执行此操作时告诉asyncio,这意味着run_in_executor
将如下所示:
sleeper
这将在单独的线程中执行睡眠(或任何其他阻塞调用)并暂停执行,直到完成为止,从而允许事件循环继续进行。请注意,“取消”这样的协程将仅放弃等待而不会真正取消睡眠,因为没有通用的机制可以这样做。