Re: [Async-sig] Inadvertent layering of synchronous code as frameworks adopt asyncio

2019-03-25 Thread Dima Tisnek
End-user point of view, a.k.a. my 2c:

re more worrisome scenario: if "objects" from two event loops depends
on each other, that's unsolvable in general case. On the other hand,
what OP wanted, was akin to DAG-like functionality or locking
hierarchy. Naive implementation would block caller callbacks until
callee completes, but that may be what the user actually wanted (?).

re ipython notebook state reuse across cells: that's a whole different
can of worms, because cells can be re-evaluated in arbitrary order. As
a user I would expect my async code to not interfere with ipynb
internal implementation. In fact, I'd rather see ipynb isolated into
own thread/loop/process. After all, I would, at times like to use a
debugger.
(full disclosure: I use debugger in ipython and it never really worked
for me in sync notebook, let alone async).

re original proposal: async code calls a synchronous function that
wants to do some async work and wait for the result, for example,
telemetry bolt-on. I would expect the 2 event loops to be isolated.
Attempting to await across loop should raise an exception, as it does.
When some application wants to coordinate things that happen in
multiple event loops, it should be the application's problem.


I think this calls for a higher-level paradigm, something that allows
suspension and resumption of entire event loops (maybe executors?) or
something that allows several event loops to run without being aware
of each other (threads?).


I feel that just adding the flag to allow creation / setting of event
loop is not enough.
We'd need at least a stack where event loops can be pushed and popped
from, and possibly more...

Cheers,
D.

On Tue, 26 Mar 2019 at 09:52, Glyph  wrote:
>
> Allowing reentrant calls to the same loop is not a good idea IMO. At best, 
> you'll need to carefully ensure that the event loop and task implementations 
> are themselves reentrancy-safe (including the C accelerators and third 
> parties like uvloop?), and then it just invites subtle issues in the 
> applications built on top of it. I don't think there's a good reason to allow 
> or support this (and nest_asyncio should be heavily discouraged). I do, 
> however, think that PBP is a good enough reason to allow opt-in use of 
> multiple event loops nested inside each other (maybe something on the 
> EventLoopPolicy for configuration?).
>
>
> +1 to all of this.
> ___
> Async-sig mailing list
> Async-sig@python.org
> https://mail.python.org/mailman/listinfo/async-sig
> Code of Conduct: https://www.python.org/psf/codeofconduct/
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] Inadvertent layering of synchronous code as frameworks adopt asyncio

2019-03-25 Thread Glyph
> As for jupyter, I think the best thing for them to do is run all notebook 
> user code in a separate thread dedicated to that purpose, and hide the fact 
> that the notebook itself is running asyncio as much as possible. That user 
> thread can start up its own event loop if it wants, but that's not the 
> jupyter kernel's concern. Until it can be refactored to use separate threads, 
> I think it would be reasonable to let it start up new event loops (and run 
> them for finite durations), although asyncio currently disallows that as long 
> as you're on the same thread as an outer event loop. 


Definitely disagree about this! If you start hiding this, then it’s impossible 
to start background tasks which run on the event loop and update a cell; not to 
mention that depending on your library (ie whether it’s something the kernel 
itself wants to import), then makes the thread that defined *some* of your 
classes at import time start being different from the thread that’s executing 
your code.

I frequently use tornado.platform.twisted to do async background work in 
notebooks and it would break a ton of my work to start requiring manual 
event-loop management that can’t persist between cells.

It’s fine for the kernel to just block for a while if it has synchronous work 
to do; that’s one of the core benefits of separating the kernels from the UI.___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] Inadvertent layering of synchronous code as frameworks adopt asyncio

2019-03-25 Thread Guido van Rossum
On Mon, Mar 25, 2019 at 5:11 PM Ben Darnell  wrote:

> On Mon, Mar 25, 2019 at 8:02 PM Guido van Rossum  wrote:
>
>>
>> Given PBP, I wonder if we should just relent and have a configurable flag
>> (off by default) to allow nested loop invocations (both the same loop and a
>> different loop).
>>
>>
> Allowing reentrant calls to the same loop is not a good idea IMO. At best,
> you'll need to carefully ensure that the event loop and task
> implementations are themselves reentrancy-safe (including the C
> accelerators and third parties like uvloop?), and then it just invites
> subtle issues in the applications built on top of it. I don't think there's
> a good reason to allow or support this (and nest_asyncio should be heavily
> discouraged). I do, however, think that PBP is a good enough reason to
> allow opt-in use of multiple event loops nested inside each other (maybe
> something on the EventLoopPolicy for configuration?).
>

Well, at least I am not alone in being very wary about nest_asyncio (and
disappointed that Jupyter recommends it).

It would certainly require carefully ensuring reentrancy of the asyncio
implementation. I guess that's one reason why nest_asyncio disables the C
accelerators and doesn't work with uvloop. Regarding reentrancy of
applications, I think that would be somewhat limited -- the critical
section I showed in my first message in this thread would still be safe, as
long as the queue implementation chooses not to call out to code that uses
run_until_complete(). We might need a convention to document whether
something runs an event loop (in the strict asyncio philosophy this
convention is `async def` of course :-).

I guess calling out to a different event loop is no worse than calling out
to requests -- I consider both strong violations of asyncio's ideals.

-- 
--Guido van Rossum (python.org/~guido)
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] Inadvertent layering of synchronous code as frameworks adopt asyncio

2019-03-25 Thread Ben Darnell
On Mon, Mar 25, 2019 at 8:02 PM Guido van Rossum  wrote:

>
> Given PBP, I wonder if we should just relent and have a configurable flag
> (off by default) to allow nested loop invocations (both the same loop and a
> different loop).
>
>
Allowing reentrant calls to the same loop is not a good idea IMO. At best,
you'll need to carefully ensure that the event loop and task
implementations are themselves reentrancy-safe (including the C
accelerators and third parties like uvloop?), and then it just invites
subtle issues in the applications built on top of it. I don't think there's
a good reason to allow or support this (and nest_asyncio should be heavily
discouraged). I do, however, think that PBP is a good enough reason to
allow opt-in use of multiple event loops nested inside each other (maybe
something on the EventLoopPolicy for configuration?).

-Ben
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] Inadvertent layering of synchronous code as frameworks adopt asyncio

2019-03-25 Thread Guido van Rossum
On Mon, Mar 25, 2019 at 4:54 PM Ben Darnell  wrote:

> On Mon, Mar 25, 2019 at 7:37 PM Guido van Rossum  wrote:
>
>> Thanks for bringing this up -- I think it will be good to get to the
>> bottom of this, before the Jupyter folks accidentally get everyone to use
>> an approach that is unsound. Maybe they can be redirected to a better
>> strategy, or maybe they can convince us to change asyncio: it's totally
>> possible that the reasoning behind this restriction is no longer really
>> valid.
>>
>> I expect that Yury will have to jump in, but I believe he's busy with a
>> release. I also hope Nathaniel has something to say -- I wonder if trio
>> supports nested event loops? (And maybe a Tornado developer?)
>>
>
> Tornado does allow for nested event loops (or did, before we adopted
> asyncio). It doesn't allow nested invocations of the *same* event loop.
>

Good to know.


> One final thing. What we're talking about here is nested invocation of the
>> "event pump". There's another form of nested event loop invocation where
>> two separate event loop objects exist. That is a much more worrisome
>> scenario, because callbacks associated with one event loop won't run at all
>> while one is waiting for a task on the other loop. Fortunately that's not
>> what is requested here. :-)
>>
>
> I actually think that nesting multiple event loops is not so problematic,
> or at least not so problematic to be worth explicitly prohibiting. You
> wouldn't want to run_forever an inner event loop while an outer one is
> blocked, but using an inner short-lived event loop is not so bad. It's not
> good, because it does block the outer event loop, but there are plenty of
> things you could do that do that - use requests instead of an async http
> client, use an inner event loop from a different library that you can't
> detect, etc. Why single out nesting one asyncio event loop inside another
> as something to prohibit?
>

Hm, I didn't mean to single out nesting asyncio. According to (the extreme
version of) asyncio's philosophy, *anything* that does I/O is a no-no.
(Yes, some people feel even disk I/O should be done asynchronously, and
there's a real implementation of that somewhere. Trio supports this:
https://trio.readthedocs.io/en/latest/reference-io.html#asynchronous-filesystem-i-o
.)


> In the past, when I converted a django app to use tornado I went through a
> phase where there were multiple nested IOLoops. First convert all the
> outgoing network calls (which I guess were urllib2 at the time; requests
> didn't exist yet) to spin up a short-lived IOLoop and run tornado's
> AsyncHTTPClient (using the equivalent of IOLoop.run_sync, although that
> method hadn't been added yet). Then replace the outer django handlers with
> tornado handlers one at a time (using tornado's WSGIContainer to run the
> django parts). Once WSGIContainer was gone, I could change all the run_sync
> calls to yields so everything ran on the outer event loop. It wasn't the
> prettiest or fastest thing I've ever done, but it worked.
>

I have to admit that practicality probably beats purity here.


> As for jupyter, I think the best thing for them to do is run all notebook
> user code in a separate thread dedicated to that purpose, and hide the fact
> that the notebook itself is running asyncio as much as possible. That user
> thread can start up its own event loop if it wants, but that's not the
> jupyter kernel's concern. Until it can be refactored to use separate
> threads, I think it would be reasonable to let it start up new event loops
> (and run them for finite durations), although asyncio currently disallows
> that as long as you're on the same thread as an outer event loop.
>

Given PBP, I wonder if we should just relent and have a configurable flag
(off by default) to allow nested loop invocations (both the same loop and a
different loop).

-- 
--Guido van Rossum (python.org/~guido)
___
Async-sig mailing list
Async-sig@python.org
https://mail.python.org/mailman/listinfo/async-sig
Code of Conduct: https://www.python.org/psf/codeofconduct/


Re: [Async-sig] Inadvertent layering of synchronous code as frameworks adopt asyncio

2019-03-25 Thread Guido van Rossum
Thanks for bringing this up -- I think it will be good to get to the bottom
of this, before the Jupyter folks accidentally get everyone to use an
approach that is unsound. Maybe they can be redirected to a better
strategy, or maybe they can convince us to change asyncio: it's totally
possible that the reasoning behind this restriction is no longer really
valid.

I expect that Yury will have to jump in, but I believe he's busy with a
release. I also hope Nathaniel has something to say -- I wonder if trio
supports nested event loops? (And maybe a Tornado developer?)

In the meantime, my take on this is that a nested event loop invocation by
a nominally synchronous function, i.e. something that calls
run_until_complete(), violates a guarantee that asyncio makes: callbacks
may only run when `await` is called, and thus any state that is shared
between callbacks or tasks is implicitly protected from mutation *between*
`await` calls. This means that asyncio programmers don't have to worry
about a class of nasty threading bugs caused by arbitrary interleaving of
threads. For example, take these three lines from asyncio/queue.py:

self._put(item)
self._unfinished_tasks += 1
self._finished.clear()

Because there's no `await` visible here, as a reader I know that the
accounting of finished and unfinished tasks here will always be in a
consistent state when some other piece of code receives control.

Also, I looked into nest_asyncio, and I definitely think it should not be
recommended -- it disables use of the asyncio accelerator classes
implemented in C (starting with Python 3.6).

One final thing. What we're talking about here is nested invocation of the
"event pump". There's another form of nested event loop invocation where
two separate event loop objects exist. That is a much more worrisome
scenario, because callbacks associated with one event loop won't run at all
while one is waiting for a task on the other loop. Fortunately that's not
what is requested here. :-)

--Guido

On Fri, Mar 22, 2019 at 10:00 AM Daniel Nugent  wrote:

> Hello, I was hoping that the Async SIG might have some suggestions on how
> to deal with this sort of issue:
>
> More frameworks are adopting asyncio as time marches on. A notable example
> of this is Jupyter and the Python kernels it supports (please see
> announcement here: blog.jupyter.org/ipython-7-0-async-repl-a35ce050f7f7).
> This was enabled by a change in Tornado version 5.0 to support the asyncio
> event loop.
>
> The problem is that this makes any code which inadvertently ran an asyncio
> event loop (that is, calls through a blocking API provided by a library
> implemented in asyncio) fail. The Jupyter developers seem to feel that this
> is a deficiency in the asyncio event loop model and suggest all users
> encountering such a problem adopt the patch module nest_asyncio (
> github.com/jupyter/notebook/issues/3397#issuecomment-419474214).
>
> However, it is my understanding that the Python team strongly feels this
> is not the correct path: bugs.python.org/issue33523
> bugs.python.org/issue29558bugs.python.org/issue22239
>
> I have been trying to figure out the right way to work around this issue
> such that a library implemented with asyncio that provides a synchronous
> API will not cause a problem and have come up short thus far. I was
> considering investigating the janus sync/async queue as a way of
> facilitating communication between the different modes, but I am not sure
> that the scenario I describe reflects the intended usage. That is, an outer
> asyncio driven program fragment calls into middle synchronous code, which
> calls to inner asynchronous code. It seems that janus is mostly intended to
> facilitate communication between a single outer asynchronous layer and an
> inner synchronous layer. However, the documentation is a little sparse so I
> may just not understand it yet.
>
> I don't believe I'm the only person struggling to figure out how to deal
> with this sort of situation, so I think this would be useful for the
> community to figure out a solid answer to. For example, I found this blog
> post which outlines the same sort of problem and suggests that they elected
> to use nest_asyncio threespeedlogic.com/python-tworoutines.html
>
> If anyone could provide guidance on how to go forward, I would appreciate
> it.
>
> I would also like to understand the decision making around not allowing
> event loop nesting/reentrancy as seen in the bugs.python.orgissues I
> referenced so that I may explain the tradeoffs of possibly adopting the
> nest_asyncio patch module (for the sake of argument, lets ignore the
> possible issues with non-standard event loops) better to my peers.
>
> Thank you,
>
> -Dan Nugent
> ___
> Async-sig mailing list
> Async-sig@python.org
> https://mail.python.org/mailman/listinfo/async-sig
> Code of Conduct: https://www.python.org/psf/codeofconduct/
>


-- 
--Guido van