调用 ensure_future 是包装协程结果的正确方法吗?
Is calling ensure_future the right way to wrap up the results of coroutines?
我仍然不确定何时使用 ensure_future
,我想知道在这种情况下我是否会 want/need 它。
考虑以下代码
import asyncio
loop = asyncio.get_event_loop()
async def do_work(count):
for i in range(count):
if i % 10000 == 0:
await asyncio.sleep(0.1)
print(count)
return i
async def do_batch_work():
res1 = do_work(100000)
res2 = do_work(100)
await asyncio.wait([res1, res2])
return res1, res2
def main():
loop = asyncio.get_event_loop()
res1, res2 = loop.run_until_complete(do_batch_work())
print(res1.result())
print(res2.result())
loop.close()
main()
这会打印:
100
100000
Traceback (most recent call last):
File "more_async.py", line 30, in <module>
main()
File "more_async.py", line 26, in main
print(res1.result())
AttributeError: 'coroutine' object has no attribute 'result'
异步代码按预期运行并按预期顺序打印出来,但 loop.run_until_complete(...)
不让我访问底层结果,因为 coroutine
对象似乎没有获取结果的方法。
我可以通过如下更改方法来解决这个问题
async def do_batch_work():
res1 = asyncio.ensure_future(do_work(100000))
res2 = asyncio.ensure_future(do_work(100))
await asyncio.wait([res1, res2])
return res1, res2
通过调用 asyncio.ensure_future(...)
,我确保 Task
s 回到我可以调用 result()
的地方。
我想知道,这是正确的处理方式吗?如果我关心协程的结果或者是否有其他我不知道的方法,是否需要使用 ensure_future
?
async def do_batch_work():
res1 = do_work(100000)
res2 = do_work(100)
await asyncio.wait([res1, res2])
return res1, res2
res1
和 res2
在该示例中只是协程,而不是 Future
对象,因此没有结果属性。当您使用 ensure_future()
时,res1
和 res2
现在是 Future
对象,这就是您可以访问结果属性的原因。 wait()
在这两种情况下的工作方式相同,并且两种代码的结果相同,只是您的函数没有 return 正确的对象。
如果您想修改您的第一个示例,您想要的 Future
个对象被 wait()
编辑为第一个项目。
async def do_batch_work():
res1 = do_work(100000)
res2 = do_work(100)
(res1, res2), _ = await asyncio.wait([res1, res2])
return res1, res2
您的代码非常好 - 它可以正常工作,而且我认为 asyncio 仍然没有制定一些强有力的标准。但是如果你只是想 运行 协程并行,还有另一种方式,而且见得比较多。
Gather 的文档是不言自明的,它 returns 未来带有结果列表,这里是您的代码示例:
async def do_batch_work():
res1 = do_work(100000)
res2 = do_work(100)
return await asyncio.gather(res1, res2)
def main():
loop = asyncio.get_event_loop()
res1, res2 = loop.run_until_complete(do_batch_work())
print(res1)
print(res2)
loop.close()
我仍然不确定何时使用 ensure_future
,我想知道在这种情况下我是否会 want/need 它。
考虑以下代码
import asyncio
loop = asyncio.get_event_loop()
async def do_work(count):
for i in range(count):
if i % 10000 == 0:
await asyncio.sleep(0.1)
print(count)
return i
async def do_batch_work():
res1 = do_work(100000)
res2 = do_work(100)
await asyncio.wait([res1, res2])
return res1, res2
def main():
loop = asyncio.get_event_loop()
res1, res2 = loop.run_until_complete(do_batch_work())
print(res1.result())
print(res2.result())
loop.close()
main()
这会打印:
100
100000
Traceback (most recent call last):
File "more_async.py", line 30, in <module>
main()
File "more_async.py", line 26, in main
print(res1.result())
AttributeError: 'coroutine' object has no attribute 'result'
异步代码按预期运行并按预期顺序打印出来,但 loop.run_until_complete(...)
不让我访问底层结果,因为 coroutine
对象似乎没有获取结果的方法。
我可以通过如下更改方法来解决这个问题
async def do_batch_work():
res1 = asyncio.ensure_future(do_work(100000))
res2 = asyncio.ensure_future(do_work(100))
await asyncio.wait([res1, res2])
return res1, res2
通过调用 asyncio.ensure_future(...)
,我确保 Task
s 回到我可以调用 result()
的地方。
我想知道,这是正确的处理方式吗?如果我关心协程的结果或者是否有其他我不知道的方法,是否需要使用 ensure_future
?
async def do_batch_work():
res1 = do_work(100000)
res2 = do_work(100)
await asyncio.wait([res1, res2])
return res1, res2
res1
和 res2
在该示例中只是协程,而不是 Future
对象,因此没有结果属性。当您使用 ensure_future()
时,res1
和 res2
现在是 Future
对象,这就是您可以访问结果属性的原因。 wait()
在这两种情况下的工作方式相同,并且两种代码的结果相同,只是您的函数没有 return 正确的对象。
如果您想修改您的第一个示例,您想要的 Future
个对象被 wait()
编辑为第一个项目。
async def do_batch_work():
res1 = do_work(100000)
res2 = do_work(100)
(res1, res2), _ = await asyncio.wait([res1, res2])
return res1, res2
您的代码非常好 - 它可以正常工作,而且我认为 asyncio 仍然没有制定一些强有力的标准。但是如果你只是想 运行 协程并行,还有另一种方式,而且见得比较多。
Gather 的文档是不言自明的,它 returns 未来带有结果列表,这里是您的代码示例:
async def do_batch_work():
res1 = do_work(100000)
res2 = do_work(100)
return await asyncio.gather(res1, res2)
def main():
loop = asyncio.get_event_loop()
res1, res2 = loop.run_until_complete(do_batch_work())
print(res1)
print(res2)
loop.close()