[英]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.