[Python-ideas] Chaining asyncio futures?

Mark E. Haase mehaase at gmail.com
Thu Jun 30 03:23:42 EDT 2016


Other async frameworks have constructs similar to asyncio.Future, e.g.
JavaScript has Promise[1] and Dart has a Completer/Future pair[2][3]. (For
the purpose of this e-mail, I'll call the generic concept a "Future".)

JavaScript and Dart allow futures to be chained, such that one Future's
callback is invoked only when the other Future completes. For example,
consider an API that fetches a string from a URL and returns it, but also
has an MRU cache. This API returns a Future because the caller does not
know in advance if the string to be retrieved is cached or not. If the
string is in cache, then the Future can complete immediately, but if the
string it not in cache, then the string needs to be fetched over the
network, perhaps by calling some API that returns a Future string. In this
case, it would be nice to return a Future string that is chained to the
HTTP request's future string.[4]

I tried doing this with asyncio.Future:

    import asyncio

    f1 = asyncio.Future()
    f2 = asyncio.Future()
    f2.add_done_callback(lambda f: print('done: {}'.format(f.result())))
    f2.set_result(f1)
    f1.set_result('hello world!')

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

Output:

    done: <Future finished result='hello world!'>

This does not make f2 dependent on f1; it immediately sets f2's result to
repr(f1). It's easy to modify the example so that f1's callback explicitly
sets f2's result. Abstracting a bit, we can write a chain_futures()
function.

    def chain_futures(a, b):
        a.add_done_callback(lambda _: b.set_result(a.result()))

    f3 = asyncio.Future()
    f4 = asyncio.Future()
    f4.add_done_callback(lambda f: print('done: {}'.format(f.result())))
    chain_futures(f3, f4)
    f3.set_result('hello world!')

    loop.run_until_complete(f4)

Output:

    done: hello world!

Wouldn't this be a nice feature in asyncio.Future? E.g. instead of
`chain_futures(f3, f4)`, either `f3.set_result(f4)` or something more
explicit like `f3.set_result_from(f4)`.


[1]
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
[2] https://api.dartlang.org/stable/1.17.1/dart-async/Completer-class.html
[3] https://api.dartlang.org/stable/1.17.1/dart-async/Future-class.html
[4] Why not return the HTTP request Future directly? That feels hacky --
it's a leaky abstraction.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20160630/f4339c80/attachment.html>


More information about the Python-ideas mailing list