I have a coroutine which I'd like to run as a "background job" in a Jupyter notebook. I've seen ways to accomplish this using threading, but I'm wondering whether it's also possible to hook into the notebook's event loop.
For example, say I have the following class:
import asyncio
class Counter:
def __init__(self):
self.counter = 0
async def run(self):
while True:
self.counter += 1
await asyncio.sleep(1.0)
t = Counter()
and I'd like to execute the run method (which loops indefinitely), while still being able to check the t.counter
variable at any point. Any ideas?
You can put the process into the background by using jupyter notebook --no-browser & disown . You can close the terminal afterwards and the process will still be running. If you're using zsh you can also use a shorter version that does the same: jupyter notebook --no-browser &! .
Capturing Output With %%capture IPython has a cell magic, %%capture , which captures the stdout/stderr of a cell. With this magic you can discard these streams or store them in a variable. By default, %%capture discards these streams. This is a simple way to suppress unwanted output.
Open a Jupyter notebook from the left sidebar. Click on the Scheduler icon either from the left sidebar tab or from the top toolbar of the Jupyter notebook. The left sidebar displays the Schedule(s) and Run History tabs as shown below. To view the active schedules, click Schedule(s) tab.
This can be done by typing jupyter notebook in the terminal, which will open a browser. Then, navigate to the respective jupyter notebook file in the browser and open it. Click Cell > Run All on the toolbar. All done!
The following basically does what I want I think, but it does use a separate thread. However, I can still use the async primitives.
def run_loop():
loop = asyncio.new_event_loop()
run_loop.loop = loop
asyncio.set_event_loop(loop)
task = loop.create_task(t.run())
loop.run_until_complete(task)
from IPython.lib import backgroundjobs as bg
jobs = bg.BackgroundJobManager()
jobs.new('run_loop()')
loop = run_loop.loop # to access the loop outside
I think your code works perfectly, you just need to create a task to wrap the coroutine, i.e. :
import asyncio
class Counter:
def __init__(self):
self.counter = 0
async def run(self):
while True:
self.counter += 1
await asyncio.sleep(1.0)
t = Counter()
asyncio.create_task(t.run())
wait 10 seconds, and check
t.counter
should get
> 10
There's a simplified version of what Mark proposed:
from IPython.lib import backgroundjobs as bg
jobs = bg.BackgroundJobManager()
jobs.new(asyncio.get_event_loop().run_forever)
If you need, you can access the loop with asyncio.get_event_loop()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With