从后台线程与输出部件交互

从后台线程与输出部件交互#

在显示由后台线程产生的输出时,Jupyter 的 display 机制可能违反直觉。后台线程的输出被打印到主线程当前正在写入的任何单元格。要直接看到这一点,创建一个反复打印标准输出的线程:

import threading
import time

def run():
    for i in itertools.count(0):
        time.sleep(1)
        print('output from background {}'.format(i))
        
t = threading.Thread(target=run)
t.start()

这总是在当前活动单元格中打印,而不是启动后台线程的单元格。

这可能导致输出部件出现意外行为。在输出部件捕获输出的时间内,笔记本中生成的任何输出,无论线程如何,都会进入输出部件。

避免意外的最佳方式是永远不要在多个线程生成输出的环境中使用输出部件的上下文管理器。相反,我们可以将输出部件传递给在线程中执行的函数,并使用 append_display_data()append_stdout()append_stderr() 方法将可显示的输出附加到输出部件。

import threading
from IPython.display import display, HTML
import ipywidgets as widgets
import time

def thread_func(something, out):
    for i in range(1, 5):
        time.sleep(0.3)
        out.append_stdout('{} {} {}\n'.format(i, '**'*i, something))
    out.append_display_data(HTML("<em>All done!</em>"))

display('Display in main thread')
out = widgets.Output()
# Now the key: the container is displayed (while empty) in the main thread
display(out)

thread = threading.Thread(
    target=thread_func,
    args=("some text", out))
thread.start()
'Display in main thread'
thread.join()