正确使用循环。create_Future

问题描述

我正在阅读Python文档和PyMotW书,试图学习异步/等待、未来和任务。

Coroutines and Tasks documentation:

通常不需要在应用程序中创建Future对象 级别代码。

从future documentation它说明以下内容:

loop.create_Future()

创建附加到事件循环的异步.Future对象。

这是在Asyncio中创建期货的首选方式。这使第三方事件循环可以提供 将来的对象(具有更好的性能或检测)。

但是,在PyMotW chapter on Future中,作者创建了一个future对象,如下所示:

all_done = asyncio.Future()

我假设是因为这本书稍微落后于当前版本的Python。为了更正此问题,我执行了以下操作:

future_Obj = event_loop.create_future()

因此作者的完整代码变为:

import asyncio


def mark_done(future, result):
    print('setting future result to {!r}'.format(result))
    future.set_result(result)


event_loop = asyncio.get_event_loop()

try:

    future_Obj = event_loop.create_future()
    print('scheduling mark_done')
    event_loop.call_soon(mark_done, future_Obj, 'the result')

    print('entering event loop')
    result = event_loop.run_until_complete(future_Obj)
    print('returned result: {!r}'.format(result))
finally:
    print('closing event loop')
    event_loop.close()

print('future result: {!r}'.format(future_Obj.result()))

问题:

上述示例中的future_Obj = event_loop.create_future()是根据文档创建future对象的正确方式吗?


解决方案

上述示例中的future_Obj = event_loop.create_future()是根据文档创建未来对象的正确方式吗?

是的,在如图所示的代码中,这正是执行此操作的方法。

需要注意的一件事是,未来绑定到事件循环,因此在顶级创建未来会创建绑定到asyncio.get_event_loop()最初返回的循环的未来。一旦切换到asyncio.run,您将收到一个错误,因为每次调用asyncio.run都会创建一个新的事件循环。

要避免该问题,可以从None开始,并根据需要使用global在协程中创建顶级未来。由于您显式地传递了未来(这是一个很好的做法),所以根本不需要全局变量:

def mark_done(future, result):
    print('setting future result to {!r}'.format(result))
    future.set_result(result)

async def main():
    loop = asyncio.get_event_loop()
    future = loop.create_future()
    print('scheduling mark_done')
    loop.call_soon(mark_done, future, 'the result')
    print('suspending the coroutine')
    result = await future
    print('awaited result: {!r}'.format(result))
    print('future result: {!r}'.format(future.result()))
    return result

if __name__ == '__main__':
    print('entering the event loop')
    result = asyncio.run(main())
    print('returned result: {!r}'.format(result))
请注意,使用asyncio.run时,您不需要显式关闭循环,这是自动完成的。如果您使用的是Python 3.6或更早版本,则可以将asyncio.run(main())替换为asyncio.get_event_loop().run_until_complete(main())

相关文章