erdewit / nest_asyncio

Patch asyncio to allow nested event loops
BSD 2-Clause "Simplified" License
693 stars 79 forks source link

fix: preempt native tasks in _run_once #80

Closed charles-cooper closed 8 months ago

charles-cooper commented 1 year ago

pre-empt the currently running task by removing it from _current_tasks before _run_once() and putting it back after. this solves a bug where an unpatchable task (a C object, created before apply() was called) may try to call (the C implementation of) enter_task().

(in theory) fixes #22

zduvall commented 8 months ago

Thanks for the work on this @charles-cooper. Seems to fix a bug I ran into as well. In some cases, when an exception was raised in a nested loop, I got a runtime error in a jupyter notebook:

RuntimeError: Cannot enter into task <Task pending name=...> wait_for=<_GatheringFuture finished exception=...)> cb=..., Task.task_wakeup()]> while another task <Task pending name='Task-1' coro=<...> cb=[gather.<locals>._done_callback() at ...]> is being executed.

...and outside the notebook, the code just hangs. With your fix, the execution stopped with original Exception being raised.

Hoping this can be merged or get some feedback soon!

baswelsh commented 8 months ago

Same thing here. Could we get an ETA on a release date for this?

erdewit commented 8 months ago

Thanks @charles-cooper for the PR and @zduvall for the friendly reminder. The PR as-is doesn't work for me as just running

import nest_asyncio
nest_asyncio.apply()

in Jupyter lab raises the exception

RuntimeError: Leaving task <Task pending name='Task-3' coro=<Kernel.dispatch_queue() running at /usr/local/lib/python3.12/site-packages/ipykernel/kernelbase.py:524> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[IOLoop.add_future.<locals>.<lambda>() at /usr/local/lib64/python3.12/site-packages/tornado/ioloop.py:685]> does not match the current task None.

The idea behing the PR of preempting the current task before running a handle is I think very good. By being able to run unpatched tasks there is no need to patch any task anymore, which means the Task patching code can be scrapped (which is a nice bonus). I will look into this.