1 回答

TA貢獻1886條經驗 獲得超2個贊
asyncio通過在作為協程實現的任務之間切換來工作。一個協同程序是一個合作的程序,在協程自愿放棄控制權曾經在一段時間,以讓該asyncio事件循環切換到另一個任務。這與線程不同,在線程中每個任務可以并且將被調度程序“隨意”中斷。
并且協程每次await在另一個協程上使用時都會放棄控制,通常是在涉及某些 I/O 的地方。I/O 很慢,asyncio事件循環負責監控 I/O 流的變化,以便它可以知道哪些任務準備好再次做更多的工作。
你的問題是你有一個不合作的協程:
async def run():
for i in range(10):
if i == 5:
e.set()
print(i)
該例程沒有await語句,因此它永遠不會放棄對事件循環的控制。不能運行其他協程。
你可以等待一個asyncio.sleep()電話:
async def run():
for i in range(10):
if i == 5:
e.set()
print(i)
await asyncio.sleep(0.01) # wait 1/100th of a second
另一種選擇是將print(i)調用(這是一個 I/O 操作)替換為使用非阻塞輸出流的調用。如果您不在 Windows 上,則可StreamWriter以為以下對象創建異步 I/O 包裝器sys.stdout:
import os
import sys
async def run():
# create an async writer for sys.stdout
loop = asyncio.get_event_loop()
writer_transport, writer_protocol = await loop.connect_write_pipe(
asyncio.streams.FlowControlMixin, os.fdopen(sys.stdout.fileno(), 'wb'))
writer = asyncio.streams.StreamWriter(
writer_transport, writer_protocol, None, loop)
for i in range(10):
if i == 5:
e.set()
writer.write(b'%d\n' % i)
await writer.drain()
不幸的是,尚不支持為 Windows 控制臺流創建異步 I/O 流,請參閱Pyton 問題 #26832,您必須改用線程池執行程序。
請注意,甚至與后者協同程序,也不能保證該stop協程將實際運行不久后,足以e.set()被稱為取消run()它讀取前10名!在處理之后,循環可以自由地將控制權交還給同一個協程await writer.drain()。向sys.stdout流緩沖區寫入短行很快,唯一要做.drain()的就是讓寫入協程有時間刷新內部傳輸緩沖區;sys.stdout大多數情況下直接非阻塞寫入成功,這并不總是有足夠的空間stop_loop()來跳入,run()協程會將其所有行都寫入寫入器傳輸。
添加回答
舉報