A ContextManager for keeping threaded output associated with a cell, even after moving on.
import sys
import threading
import time
from contextlib import contextmanager
# we need a lock, so that other threads don't snatch control
# while we have set a temporary parent
stdout_lock = threading.Lock()
@contextmanager
def set_stdout_parent(parent):
"""a context manager for setting a particular parent for sys.stdout
the parent determines the destination cell of output
"""
save_parent = sys.stdout.parent_header
with stdout_lock:
sys.stdout.parent_header = parent
try:
yield
finally:
# the flush is important, because that's when the parent_header actually has its effect
sys.stdout.flush()
sys.stdout.parent_header = save_parent
Just use this tic as a marker, to show that we really are printing to two cells simultaneously
tic = time.time()
class counterThread(threading.Thread):
def run(self):
# record the parent when the thread starts
thread_parent = sys.stdout.parent_header
for i in range(3):
time.sleep(2)
# then ensure that the parent is the same as when the thread started
# every time we print
with set_stdout_parent(thread_parent):
print i, "%.2f" % (time.time() - tic)
for i in range(3):
counterThread().start()
0 2.05 0 2.05 0 2.05 1 4.05 1 4.05 1 4.05 2 6.06 2 6.06 2 6.06
for i in range(3):
counterThread().start()
0 2.07 0 2.07 0 2.07 1 4.07 1 4.07 1 4.08 2 6.08 2 6.08 2 6.08