[Python-ideas] Submitting a job to an asyncio event loop

Vincent Michel vxgmichel at gmail.com
Sat Sep 26 16:29:12 CEST 2015


Hi,

I noticed there is currently no standard solution to submit a job from a
thread to an asyncio event loop.

Here's what the asyncio documentation says about concurrency and
multithreading:

> To schedule a callback from a different thread, the
BaseEventLoop.call_soon_threadsafe() method should be used.
> Example to schedule a coroutine from a different thread:
>     loop.call_soon_threadsafe(asyncio.async, coro_func())

The issue with this method is the loss of the coroutine result.

One way to deal with this issue is to connect the asyncio.Future returned
by async (or ensure_future) to a concurrent.futures.Future. It is then
possible to use a subclass of concurrent.futures.Executor to submit a
callback to an asyncio event loop. Such an executor can also be used to set
up communication between two event loops using run_in_executor.

I posted an implementation called LoopExecutor on GitHub:
https://github.com/vxgmichel/asyncio-loopexecutor
The repo contains the loopexecutor module along with tests for several use
cases. The README describes the whole thing (context, examples, issues,
implementation).

It is interesting to note that this executor is a bit different than
ThreadPoolExecutor and ProcessPoolExecutor since it can also submit a
coroutine function. Example:

with LoopExecutor(loop) as executor:
    future = executor.submit(operator.add, 1, 2)
    assert future.result() == 3
    future = executor.submit(asyncio.sleep, 0.1, result=3)
    assert future.result() == 3

This works in both cases because submit always cast the given function to a
coroutine. That means it would also work with a function that returns a
Future.

Here's a few topic related to the current implementation that might be
interesting to discuss:

- possible drawback of casting the callback to a coroutine
- possible drawback of concurrent.future.Future using
asyncio.Future._copy_state
- does LoopExecutor need to implement the shutdown method?
- removing the limitation in run_in_executor (can't submit a coroutine
function)
- adding a generic Future connection function in asyncio
- reimplementing wrap_future with the generic connection
- adding LoopExecutor to asyncio (or concurrent.futures)

At the moment, the interaction between asyncio and concurrent.futures only
goes one way. It would be nice to have a standard solution (LoopExecutor or
something else) to make it bidirectional.

Thanks,

Vincent
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20150926/e95732e7/attachment.html>


More information about the Python-ideas mailing list