<p dir="ltr">+1on the name change. </p>
<div class="gmail_quote">On Aug 8, 2015 10:12 AM, "Nick Coghlan" <<a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 8 August 2015 at 03:08, Guido van Rossum <<a href="mailto:guido@python.org">guido@python.org</a>> wrote:<br>
> FWIW, I am against this (as Alex already knows), for the same reasons I<br>
> didn't like Nick's proposal. Fuzzing the difference between threads and<br>
> asyncio tasks is IMO asking for problems -- people will stop understanding<br>
> what they are doing and then be bitten when they least need it.<br>
<br>
I'm against concurrent.futures offering native asyncio support as well<br>
- that dependency already goes the other way, from asyncio down to<br>
concurrent.futures by way of the loop's pool executor.<br>
<br>
The only aspect of my previous suggestions I'm still interested in is<br>
a name and signature change from "loop.run_in_executor(executor,<br>
callable)" to "loop.call_in_background(callable, *, executor=None)".<br>
<br>
Currently, the recommended way to implement a blocking call like<br>
Alex's example is this:<br>
<br>
from asyncio import get_event_loop<br>
<br>
async def handler(self):<br>
loop = asyncio.get_event_loop()<br>
result = await loop.run_in_executor(None,<br>
some_blocking_api.some_blocking_call)<br>
await self.write(result)<br>
<br>
I now see four concrete problems with this specific method name and signature:<br>
<br>
* we don't run functions, we call them<br>
* we do run event loops, but this call doesn't start an event loop running<br>
* "executor" only suggests "background call" to folks that already<br>
know how concurrent.futures works<br>
* we require the explicit "None" boilerplate to say "use the<br>
default executor", rather than using the more idiomatic approach of<br>
accepting an alternate executor as an optional keyword only argument<br>
<br>
With the suggested change to the method name and signature, the same<br>
example would instead look like:<br>
<br>
async def handler(self):<br>
loop = asyncio.get_event_loop()<br>
result = await<br>
loop.call_in_background(some_blocking_api.some_blocking_call)<br>
await self.write(result)<br>
<br>
That should make sense to anyone reading the handler, even if they<br>
know nothing about concurrent.futures - the precise mechanics of how<br>
the event loop goes about handing off the call to a background thread<br>
or process is something they can explore later, they don't need to<br>
know about it in order to locally reason about this specific handler.<br>
<br>
It also means that event loops would be free to implement their<br>
*default* background call functionality using something other than<br>
concurrent.futures, and only switch to the latter if an executor was<br>
specified explicitly.<br>
<br>
There are still some open questions about whether it makes sense to<br>
allow callables to indicate whether or not they expect to be IO bound<br>
or CPU bound, and hence allow event loop implementations to opt to<br>
dispatch the latter to a process pool by default (I saw someone<br>
suggest that recently, and I find the idea intriguing), but I think<br>
that's a separate question from dispatching a given call for parallel<br>
execution, with the result being awaited via a particular event loop.<br>
<br>
Cheers,<br>
Nick.<br>
<br>
--<br>
Nick Coghlan | <a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a> | Brisbane, Australia<br>
</blockquote></div>