如何在启动它的单元格中打印 jupyter 后台作业输出?

how to print jupyter background job output in cell it was launched from?

从 IPython Jupyter Notebook 启动后台作业时,如何使打印输出出现在启动它的单元格中,而不是出现在我当前工作的单元格中?

print() 命令似乎打印到当前工作单元格中,而不是打印到启动后台作业的单元格中。有没有办法让它在启动它的单元格中打印得很好?这在 运行 多个后台作业集时尤为重要,以确定哪个作业集负责该行输出。

编辑:它出现在任何代码中,但这里有一个小片段可以重现它:

from IPython.lib import backgroundjobs as bg
import time
def launchJob():
    for i in range(100):
       print('x')
       time.sleep(1)
jobs = bg.BackgroundJobManager()
for r in range(3):
    jobs.new("launchJob()")

这完全符合您的预期,在单元格下的输出中每秒打印 3 个 x。现在转到下一个单元格并键入 1+1 并执行它。出现输出 2,但所有剩余的 x 也会打印在这个新单元格中,而不是原始单元格中。

我正在寻找一种方法来专门告诉我的作业始终打印到执行它的原始单元格,以便在后台获取某种日志,或者在后台生成一堆图,或我想要的任何类型的数据,而不是出现在我的笔记本上。

IPython.lib.backgoundjobs.BackgroundJobManager.new documentation 状态:

All threads running share the same standard output. Thus, if your background jobs generate output, it will come out on top of whatever you are currently writing. For this reason, background jobs are best used with silent functions which simply return their output.

在GitHub pull request #856 of IPython (October 2011), the developers discussed this issue and concluded that keeping the output in the original cell would be difficult to implement. Hence, they decided to table the idea和最新版本(撰写本文时为7.9.0)中仍未解决。

与此同时,解决方法可能是将输出存储在变量中,或者在后台作业完成后将其写入/pickle the output to a file and print/display

@Peter 由于其他答案解决了使用 pickle 或输出文件执行此操作的方法,我想建议替代方法。 我会建议您应该在父 window 中启动打印操作。当在子进程中达到某些执行标准时 window 然后 return 这些值将在父进程中打印函数。

使用%matplotlib inline打印父单元格中的值。这将在同一个单元格中打印输出和视觉效果。

虽然它不能直接回答我的问题,因为它不适用于打印命令,但我确实设法部分解决了我的问题,因为我可以在后面更新图表(因此可以记录无需重新运行).

下面的一些概念验证代码,基于

%matplotlib notebook

import numpy as np
import matplotlib.pyplot as plt
import time
from IPython.lib import backgroundjobs as bg

def pltsin(ax, colors=['b']):
    x = np.linspace(0,1,100)
    if ax.lines:
        for line in ax.lines:
            line.set_xdata(x)
            y = np.random.random(size=(100,1))
            line.set_ydata(y)
    else:
        for color in colors:
            y = np.random.random(size=(100,1))
            ax.plot(x, y, color)
    fig.canvas.draw()

fig,ax = plt.subplots(1,1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(0,1)
ax.set_ylim(0,1)

def launchJob():
    for i in range(100):
        pltsin(ax, ['b', 'r'])
        time.sleep(1)
jobs = bg.BackgroundJobManager()
jobs.new("launchJob()")

虽然这是 运行ning,但在另一个单元格中键入 1+1 不会中断图形的更新。对我来说,这是一个游戏规则的改变者,所以我会 post 以防有人能从中得到帮助。