为什么 asyncio.wait 不等待 FIRST_COMPLETED
Why asyncio.wait does not wait for the FIRST_COMPLETED
我是 Python 3.5 asyncio 的新手。
在我下面的代码中,asyncio.wait() 不等待 stop_future 完成:
import asyncio
import datetime
from concurrent.futures import FIRST_COMPLETED
def stop(): # callback after 12 seconds
print('stop', datetime.datetime.now())
stop_future.set_result('Done!')
async def display_dt():
while not stop_future.done():
print('dt-1', datetime.datetime.now())
# sleep 5 seconds or stop_future done
asyncio.wait([await asyncio.sleep(5), stop_future], return_when=FIRST_COMPLETED)
print('dt-2', datetime.datetime.now())
task = asyncio.Task.current_task()
task.cancel()
print(stop_future.result())
loop = asyncio.get_event_loop()
stop_future = asyncio.Future()
loop.call_later(12, stop)
loop.run_until_complete(display_dt())
loop.close()
结果:
dt-1 2015-11-08 00:49:37.324582
dt-2 2015-11-08 00:49:42.325503
dt-1 2015-11-08 00:49:42.325503
dt-2 2015-11-08 00:49:47.326423
dt-1 2015-11-08 00:49:47.326423
stop 2015-11-08 00:49:49.327192 # async.wait stop_future not triggered
dt-2 2015-11-08 00:49:52.327343 # while loop finishes here
>>> Done!
更新:
下面是更新函数的代码 display_dt。现在 asyncio.wait
工作正常。
但是我不明白为什么上面的coro代码不起作用??
@asyncio.coroutine # decorator necessary? It works fine without
def display_dt():
while not stop_future.done():
print('dt-1', datetime.datetime.now())
yield from asyncio.wait([asyncio.sleep(5), stop_future], return_when=FIRST_COMPLETED)
print('dt-2', datetime.datetime.now())
task = asyncio.Task.current_task()
task.cancel()
print(stop_future.result())
结果:
dt-1 2015-11-08 01:19:06.289915
dt-2 2015-11-08 01:19:11.290836
dt-1 2015-11-08 01:19:11.290836
dt-2 2015-11-08 01:19:16.291757
dt-1 2015-11-08 01:19:16.291757
stop 2015-11-08 01:19:18.292525
dt-2 2015-11-08 01:19:18.292525 # async wait stop_future triggered
Done!
更新: @asyncio.coroutine # 是否需要装饰器?
我在this great chapter中找到了答案:
@asyncio.coroutine 装饰器并不神奇。事实上,如果它装饰了一个生成器函数并且没有设置 PYTHONASYNCIODEBUG 环境变量,装饰器实际上什么都不做。它只是设置了一个属性,_is_coroutine,以方便框架的其他部分。可以将 asyncio 与根本没有用 @asyncio.coroutine 修饰的裸生成器一起使用。↩
您必须 await
.wait()
协程,而不是 await
您 传递给 的协程 .wait()
:
async def display_dt():
while not stop_future.done():
print('dt-1', datetime.datetime.now())
# sleep 5 seconds or stop_future done
await asyncio.wait([asyncio.sleep(5), stop_future], return_when=FIRST_COMPLETED) # <----
print('dt-2', datetime.datetime.now())
task = asyncio.Task.current_task()
task.cancel()
print(stop_future.result())
现在这等同于您的编辑,但使用的是 原生协程 (即 async/await
语法)。
更新 显示结果:
dt-1 2015-11-08 13:14:21.910399
dt-2 2015-11-08 13:14:26.911320
dt-1 2015-11-08 13:14:26.911320
dt-2 2015-11-08 13:14:31.912240
dt-1 2015-11-08 13:14:31.912240
stop 2015-11-08 13:14:33.913009
dt-2 2015-11-08 13:14:33.913009
Done!
我是 Python 3.5 asyncio 的新手。
在我下面的代码中,asyncio.wait() 不等待 stop_future 完成:
import asyncio
import datetime
from concurrent.futures import FIRST_COMPLETED
def stop(): # callback after 12 seconds
print('stop', datetime.datetime.now())
stop_future.set_result('Done!')
async def display_dt():
while not stop_future.done():
print('dt-1', datetime.datetime.now())
# sleep 5 seconds or stop_future done
asyncio.wait([await asyncio.sleep(5), stop_future], return_when=FIRST_COMPLETED)
print('dt-2', datetime.datetime.now())
task = asyncio.Task.current_task()
task.cancel()
print(stop_future.result())
loop = asyncio.get_event_loop()
stop_future = asyncio.Future()
loop.call_later(12, stop)
loop.run_until_complete(display_dt())
loop.close()
结果:
dt-1 2015-11-08 00:49:37.324582
dt-2 2015-11-08 00:49:42.325503
dt-1 2015-11-08 00:49:42.325503
dt-2 2015-11-08 00:49:47.326423
dt-1 2015-11-08 00:49:47.326423
stop 2015-11-08 00:49:49.327192 # async.wait stop_future not triggered
dt-2 2015-11-08 00:49:52.327343 # while loop finishes here
>>> Done!
更新:
下面是更新函数的代码 display_dt。现在 asyncio.wait
工作正常。
但是我不明白为什么上面的coro代码不起作用??
@asyncio.coroutine # decorator necessary? It works fine without
def display_dt():
while not stop_future.done():
print('dt-1', datetime.datetime.now())
yield from asyncio.wait([asyncio.sleep(5), stop_future], return_when=FIRST_COMPLETED)
print('dt-2', datetime.datetime.now())
task = asyncio.Task.current_task()
task.cancel()
print(stop_future.result())
结果:
dt-1 2015-11-08 01:19:06.289915
dt-2 2015-11-08 01:19:11.290836
dt-1 2015-11-08 01:19:11.290836
dt-2 2015-11-08 01:19:16.291757
dt-1 2015-11-08 01:19:16.291757
stop 2015-11-08 01:19:18.292525
dt-2 2015-11-08 01:19:18.292525 # async wait stop_future triggered
Done!
更新: @asyncio.coroutine # 是否需要装饰器?
我在this great chapter中找到了答案:
@asyncio.coroutine 装饰器并不神奇。事实上,如果它装饰了一个生成器函数并且没有设置 PYTHONASYNCIODEBUG 环境变量,装饰器实际上什么都不做。它只是设置了一个属性,_is_coroutine,以方便框架的其他部分。可以将 asyncio 与根本没有用 @asyncio.coroutine 修饰的裸生成器一起使用。↩
您必须 await
.wait()
协程,而不是 await
您 传递给 的协程 .wait()
:
async def display_dt():
while not stop_future.done():
print('dt-1', datetime.datetime.now())
# sleep 5 seconds or stop_future done
await asyncio.wait([asyncio.sleep(5), stop_future], return_when=FIRST_COMPLETED) # <----
print('dt-2', datetime.datetime.now())
task = asyncio.Task.current_task()
task.cancel()
print(stop_future.result())
现在这等同于您的编辑,但使用的是 原生协程 (即 async/await
语法)。
更新 显示结果:
dt-1 2015-11-08 13:14:21.910399
dt-2 2015-11-08 13:14:26.911320
dt-1 2015-11-08 13:14:26.911320
dt-2 2015-11-08 13:14:31.912240
dt-1 2015-11-08 13:14:31.912240
stop 2015-11-08 13:14:33.913009
dt-2 2015-11-08 13:14:33.913009
Done!