5

In Jupyter with an ipython kernel, is there a canonical way to execute cells in a non-blocking fashion?

Ideally I'd like to be able to run a cell

%%background
time.sleep(10)
print("hello")

such that I can start editing and running the next cells and in 10 seconds see "hello" appear in the output of the original cell.


I have tried two approaches, but haven't been happy with either.

(1) Create a thread by hand:

def foo():
    time.sleep(10)
    print("hello")
threading.Thread(target=foo).start()

The problem with this is that "hello" is printed in whatever cell is active in 10 seconds, not necessarily in the cell where the thread was started.

(2) Use a ipywidget.Output widget.

def foo(out):
    time.sleep(10)
    out.append_stdout("hello")
out = ipywidgets.Output()
display(out)
threading.Thread(target=foo,args=(out,)).start()

This works, but there are problems when I want to update the output (think of monitoring something like memory consumption):

def foo(out):
    while True:
        time.sleep(1)
        out.clear_output()
        out.append_stdout(str(datetime.datetime.now()))
out = ipywidgets.Output()
display(out)
threading.Thread(target=foo,args=(out,)).start()

The output now constantly switches between 0 and 1 lines in size, which results in flickering of the entire notebook.

This should be solvable wait=True in the call to clear_output. Alas, for me it results in the output never showing anything.

I could have asked about that issue, which seems to be a bug, specifically, but I wondered whether there is maybe another solution that doesn't require me doing all of this by hand.

Bananach
  • 2,016
  • 26
  • 51

1 Answers1

0

I've experienced some issues like this with plotting to an output, it looks like you have followed the examples in the ipywidgets documentation on async output widgets.

The other approach I have found sometimes helpful (particularly if you know the size of the desired output) is to fix the height of your output widget when you create it.

out = ipywidgets.Output(layout=ipywidgets.Layout(height='25px'))

ac24
  • 5,325
  • 1
  • 16
  • 31