Python 异步:return 与 set_result

Python asyncio: return vs set_result

你好 asyncio 专家,

如何从协程中正确地 return 结果?我需要使用 return 还是 future.set_result?

例如:

@coroutine
def do_something()
    result = yield from some_function()
    return result

@coroutine
def do_something()
    future = asyncio.Future()
    result = yield from some_function()
    future.set_result(result)

你应该只使用 return result。您的第二个示例实际上将以 returning None 而不是 result 结束。这是一个完整的例子,证明了这一点:

from asyncio import coroutine
import asyncio

@asyncio.coroutine
def some_function():
    yield from asyncio.sleep(.5)
    return 5

@coroutine
def do_something():
    result = yield from some_function()
    return result


@coroutine
def do_something_else():
    future = asyncio.Future()
    result = yield from some_function()
    future.set_result(result)

@coroutine
def main():
    print((yield from do_something()))
    print((yield from do_something_else()))

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

输出:

5
None

请注意,如果您实际上 return 来自 do_something_else:

Future,那么从调用者的角度来看,它们确实是等效的
@coroutine
def do_something_else():
    future = asyncio.Future()
    result = yield from some_function()
    future.set_result(result)
    return future # Now yield from do_something_else() returns 5.

但是当你可以直接 return result 时,这只是不必要的额外工作。

在绝大多数情况下,协程根本不需要显式创建 Future 并对其调用 set_result。该模式偶尔有用,但您大多在单元测试和框架中看到它,而不是在应用程序代码中。

它的一个有趣用途是实现 asyncio.sleep:

@coroutine
def sleep(delay, result=None, *, loop=None):
    """Coroutine that completes after a given time (in seconds)."""
    future = futures.Future(loop=loop)
    h = future._loop.call_later(delay, future.set_result, result)
    try:
        return (yield from future)
    finally:
        h.cancel()

这里创建了一个 Future,该未来的 set_result 方法被安排在调用者想要休眠多长时间后调用,然后 yield from 在未来被调用,这将使函数等待 delay 的时间,此时 future.set_result(result) 被调用,并且 yield from 调用完成。