gh-66435: Allow nested event loops#93338
Conversation
|
Most changes to Python require a NEWS entry. Please add it using the blurb_it web app or the blurb command-line tool. |
|
Please update the title to A |
|
This is different from nest_asyncio right? This PR only allows 'nested event' loops, which I think is really great (I vaex we do this using this decorator https://github.com/vaexio/vaex/blob/633970528cb5091ef376dbca2e4721cd42525419/packages/vaex-core/vaex/asyncio.py#L7 but it's using the 'nest_asyncio' will also run the tasks of the parent/previous event loop, i.e. it will give an output like this: Which basically leads to a I think with this PR it is not possible to resume a task from the previous event_loop, is that right? To make it more concrete, this example works with import asyncio
+import nest_asyncio
+
+nest_asyncio.apply()
+
+t = None
+
async def task(name):
for i in range(10):
@@ -8,6 +14,7 @@
async def bar():
+ await t
asyncio.create_task(task("bar"))
await asyncio.sleep(1.1)
print("bar done")
@@ -20,6 +27,7 @@
async def main():
+ global t
t = asyncio.create_task(task("main")) # not executed until foo() is done
foo()
await asyncio.sleep(1.1) # t resumes executionoutput: Does this PR give an exception, does it run it, or does it deadlock? I think the appropriate behavior should be an exception (complaining the awaited task |
Misc/NEWS.d/next/Library/2022-05-30-09-25-24.gh-issue-66435.E4YBFo.rst
Outdated
Show resolved
Hide resolved
|
@maartenbreddels indeed, I didn't copy exactly the code from |
If we don't, then it is not cooperative multitasking anymore. But I can't find in the Python docs that asyncio claims it is actually. In any case, it will probably break existing code. |
I think it would be less dangerous, as you mentioned, that
Yes, that's why we would need to opt-in for this behavior. |
|
@davidbrochart would it be possible for jupyter_client to spawn a python subprocess for running user code in instead? |
|
A Jupyter kernel already runs in its own process, and jupyter-client communicates with it through ZMQ sockets. |
da55551 to
d542989
Compare
|
I've simplified the changes to what I think is the minimum to get the behavior described in the top comment. Now the nested call to asyncio.run(bar(), running_ok=True) |
d542989 to
3b5df83
Compare
willingc
left a comment
There was a problem hiding this comment.
@davidbrochart @maartenbreddels If you have time to update this PR, we can discuss it at JupyterCon.
3b5df83 to
0b54e74
Compare
|
Thanks for the heads up @willingc, I rebased on import asyncio
async def task(name):
for i in range(10):
await asyncio.sleep(0.1)
print(f"from {name}: {i}")
async def bar():
asyncio.create_task(task("bar"))
await asyncio.sleep(1.1)
print("bar done")
def foo():
# asyncio.run inside an already running event loop
# pre-empts the execution of any other task in the event loop
asyncio.run(bar(), running_ok=True)
async def main():
t = asyncio.create_task(task("main")) # not executed until foo() is done
foo()
await asyncio.sleep(1.1) # t resumes execution
asyncio.run(main())That will print: If we wanted the nested call to We would not really need this PR, we would just check if a loop is already running, and if yes then call |
|
@davidbrochart Could you sign the CLA, please? #93338 (comment) |
Done. |
0b54e74 to
fd22cad
Compare
|
Whoa. A process issue: discussions about whether a particular feature should be accepted should happen on an Issue, not in a PR. The best thing to do is to reopen gh-66435, which I will do. See you there! (I do appreciate the discussion and the clear examples of two different proposed behaviors.) |
|
@davidbrochart I'm closing this PR since we decided to not add nested asyncio to the library. #66435 (comment) Thanks for your effort here and your suggestion on the issue for a third party library. |
This PR is basically a copy/paste of @erdewit's nest_asyncio library. It allows the event loop to be re-entrant, by making it possible to call
asyncio.run()inside an already running event loop.This feature request was rejected in the past, but @1st1 recently mentioned that he could reconsider this decision.
Here is an example:
This will print: