<div dir="ltr"><div><div><div><div>Hi Vincent,<br><br></div>I've read your write-up with interest. You're right that it's a bit awkward to make calls from the threaded world into the asyncio world. Interestingly, there's much better support for passing work off from the asyncio event loop to a thread (run_in_executor()). Perhaps that's because the use case there was obvious from the start: some things that may block for I/O just don't have an async interface yet, so in order to use them from an asyncio task they must be off-loaded to a separate thread or else the entire event loop is blocked. (This is used for calling getaddrinfo(), for example.)<br><br></div>I'm curious where you have encountered the opposite use case?<br><br></div>I think if I had to do this myself I would go for a more minimalist interface: something like your submit() method but without the call to asyncio.coroutine(fn). Having the caller pass in the already-called coroutine object might simplify the signature even further. I'm not sure I see the advantage of trying to make this an executor -- but perhaps I'm missing something?<br><br></div><div>--Guido<br></div><div><div><br><br></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Sep 26, 2015 at 7:29 AM, Vincent Michel <span dir="ltr"><<a href="mailto:vxgmichel@gmail.com" target="_blank">vxgmichel@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi,<br><br>I noticed there is currently no standard solution to submit a job from a thread to an asyncio event loop.<br><br>Here's what the asyncio documentation says about concurrency and multithreading:<br><br>> To schedule a callback from a different thread, the BaseEventLoop.call_soon_threadsafe() method should be used. <br>> Example to schedule a coroutine from a different thread: <br>>     loop.call_soon_threadsafe(asyncio.async, coro_func())<br><br>The issue with this method is the loss of the coroutine result.<br><br>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.<br><br>I posted an implementation called LoopExecutor on GitHub:<br><a href="https://github.com/vxgmichel/asyncio-loopexecutor" target="_blank">https://github.com/vxgmichel/asyncio-loopexecutor</a><br>The repo contains the loopexecutor module along with tests for several use cases. The README describes the whole thing (context, examples, issues, implementation).<br><br>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:<br><br>with LoopExecutor(loop) as executor:<br>    future = executor.submit(operator.add, 1, 2)<br>    assert future.result() == 3<br>    future = executor.submit(asyncio.sleep, 0.1, result=3)<br>    assert future.result() == 3<br><br>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.<br><br>Here's a few topic related to the current implementation that might be interesting to discuss:<br><br>- possible drawback of casting the callback to a coroutine<br>- possible drawback of concurrent.future.Future using asyncio.Future._copy_state<br>- does LoopExecutor need to implement the shutdown method?<br>- removing the limitation in run_in_executor (can't submit a coroutine function)<br>- adding a generic Future connection function in asyncio<br>- reimplementing wrap_future with the generic connection<br>- adding LoopExecutor to asyncio (or concurrent.futures)<br><br>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.<br><br>Thanks,<br><br>Vincent<br> <br></div>
<br>_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br></blockquote></div><br><br clear="all"><br>-- <br><div class="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
</div>