Search code examples
python-3.xpython-asynciopython-multithreadingconcurrent.futures

Can concurrent.futures.Future be converted to asyncio.Future?


I'm practicing asyncio after writing multithreaded code many years.

Noticed something which i find it strange. Both in asyncio and in concurrent there is a Future object.

from asyncio import Future
from concurrent.futures import Future

Guess each onee has it's own role..

My question is if i can transfer concurrent.future.Future to asyncio.Future (or the opposite)?


Solution

  • My question is if i can transfer concurrent.future.Future to asyncio.Future (or the opposite)?

    If by "transfer" you mean convert one to the other, yes, it's possible, although bridging the impedance mismatch can take some work.

    To convert a concurrent.futures.Future into an asyncio.Future, you can call asyncio.wrap_future. The returned asyncio future is awaitable in the asyncio event loop and will complete when the underlying threading future completes. This is effectively how run_in_executor is implemented.

    There is no public functionality to directly convert an asyncio future to concurrent.futures future, but there is the asyncio.run_coroutine_threadsafe function, which takes a coroutine, submits it to an event loop, and returns a concurrent future which completes when the asyncio future does. This can be used to effectively convert any asyncio-awaitable future to concurrent future, like this:

    def to_concurrent(fut, loop):
        async def wait():
            await fut
        return asyncio.run_coroutine_threadsafe(wait(), loop)
    

    The returned future will behave like you'd expect from a concurrent future, e.g. its result() method will block, etc. One thing you might want to be careful of is that callbacks added to the concurrent future with add_done_callback run in the thread that marked the future completed, which in this case is the event loop thread. This means that if you add some done callbacks, you need to be careful not to invoke blocking calls in their implementation lest you block the event loop.

    Note that calling run_coroutine_threadsafe requires the event loop to actually run in some other thread. (For example, you can start a background thread and have it execute loop.run_forever.)