关闭浏览器标签后仍然保持Jupyter Notebook运行

70

我使用Jupyter Notebook运行一系列需要一些时间的实验。

某些单元格的执行时间太长,因此关闭浏览器选项卡并稍后再回来是很正常的。但是这样做会导致内核中断运行。

我猜有一种解决方法,但我找不到它。

8个回答

73

最简单的解决方法似乎是使用内置的单元格魔法 %%capture

%%capture output
# Time-consuming code here

保存,关闭标签页,稍后回来。输出现在存储在output变量中:

output.show()

这将显示所有的中间print结果以及纯文本或富文本输出单元格。


38

TL;DR:

关闭标签页后,代码不会停止运行,但输出无法找到当前浏览器会话并丢失有关其应如何显示的数据,导致它抛出所有接收到的新输出,直到运行当时正在运行的代码完成。

Long Version:

很遗憾,这个功能目前还没有实现(截至11月24日)。如果有解决方法,我也找不到。 (继续寻找,将更新相关消息。)有一种解决方法可以保存输出然后重新打印,但如果代码仍在该笔记本中运行,则无法正常工作。另一种替代方法是使用第二个笔记本来获取输出。

我也需要这个功能,原因相同。关闭标签页时内核不会关闭或中断。代码也不会停止运行。警告信息非常准确,“内核正忙,可能会丢失输出。”

运行中。

import time
a = 0
while a < 100:
    a+=1
    print(a)
    time.sleep(1)

在一个框中,然后关闭标签页,再次打开它,然后运行。
print(a)

从另一个框中运行代码将导致它挂起,直到100秒完成且代码完成,然后它将打印100。
当关闭选项卡时,在返回时,Python进程将处于您离开时的相同状态(最后一次保存完成时)。这是他们预期的行为,并且在文档中应该更清楚地说明。实际上,从运行代码输出发送到重新打开它的浏览器(失去了解释此功能的参考),因此像此评论中的Hack将起作用,因为它可以接收它们并将它们扔进某个单元格。
通过端点连接,输出仅以可访问的方式保存。 他们一直在这方面进行工作(在Jupyter之前),尽管我找不到Jupyter存储库中的当前错误(这个引用它,但不是它)。
唯一的通用解决方法似乎是找到一个始终可以保持打开状态的计算机,并在其运行页面时将其保持打开状态,然后远程登录或依赖自动保存以能够在其他地方访问它。这是一种糟糕的方法,但不幸的是,现在我必须这样做。
相关问题:

我认为当标签页关闭时,代码实际上并没有被中断。但是,输出是被中断的,就像你所说的那样。因此,我使用的不太优雅的解决方法是将计算结果存储在一种易于重新生成输出的方式中。特别是,我正在存储分类的混淆矩阵和ROC曲线,只需重新绘制它们即可。 - ijoseph
1
你说得对。我终于重新测试了一下。很好的发现。我还从Jupyter和IPython的错误列表中获得了更多详细信息。我会找到它们并更新帖子。 - Poik
1
当通过菜单命令“运行全部”来运行整个笔记本时,情况如何?执行会在一个单元格后停止吗? - IanS
@IanS 这是一个好问题。我会回复你的,除非有人比我更快。 - Poik
1
谢谢!我进行了一些实验,我相当确定整个笔记本都执行了。当然,输出是丢失的,但所有单元格都运行到了最后。 - IanS
我个人通过使用pygsheets库将重要的输出存储在Google电子表格中来解决了这个问题。这样,无论浏览器活动如何,输出都会被保存。 - spacediver

9
首先,安装
runipy

pip install runipy

现在使用以下命令在后台运行你的笔记本:

nohup runipy YourNotebook.ipynb OutputNotebook.ipynb >> notebook.log &

现在输出文件将被保存,您还可以通过以下方式查看运行日志:

tail -f notebook.log

1
现在,如果你这样做,即使程序运行10个小时以上,它也会持续运行吗? - Xhuliano Brace
是的,它会一直运行程序直到你停止它。 - Saitejareddy
OutputNotebook是什么? - Kitwradr
OutputNotebook是什么? - undefined

4

使用 JupyterLab:

如果您使用的是JupyterLab(当前版本为v3.x.x),那么这不是一个问题。

更具体地说,不是问题指的是,在关闭选项卡/浏览器后,笔记本的内核仍在运行(只要jupyter服务器/终端没有关闭)。但是,单元格的打印输出(如果有)会被中断。

因此,当我们重新打开笔记本时,变量等都会保留并更新,但是被中断的打印输出不会显示。

如果您关心此情况下的打印信息,可以尝试将其记录到文件中。或者尝试使用Jupyter的执行API(请参见下文)。


使用 Jupyter Notebook:

如果您仍然坚持使用旧版(例如版本5.x / 6.x)Jupyter Notebook,那么在过去(即2022年之前)也无法解决这个问题。

但是,计划中的新Notebook v7版本将重用JupyterLab代码库,这个问题也将在新的Jupyter Notebook中得到解决。

因此,建议使用JupyterLab或等待并更新到Notebook v7

$ jupyter lab --version
$ 3.4.4
$ # OR waite and update the notebook, untill
$ # make sure the installed version of notebook is v7
$ jupyter notebook --version
$ 6.4.12

使用Jupyter的执行API:

另一个解决方法是使用Jupyter的执行API

$ jupyter nbconvert --to notebook --execute mynotebook.ipynb

这就像在命令行下运行笔记本一样,而不是在Web浏览器UI模式下。执行后,将产生一个名为“mynotebook.nbconvert.ipynb”的新文件,并且所有打印输出都将保留在其中,但所有变量都将丢失。我们可以做的是对我们关心的变量进行pickling。我认为使用runipy已经不是一个好选择了,因为它已经被弃用和未维护(在Jupyter的execute API之后)。参考:https://github.com/jupyter/notebook/issues/2446#issuecomment-1035210255 引用: 问:即使页面关闭,是否仍然可以使jupyter notebook运行? 答:这正在JupyterLab中解决,并将在未来的Notebook v7版本中解决。

2
这在JupyterLab中不起作用。我刚测试过了。问题是一样的——笔记本断开连接,不再接收输出。所引用的文档仅显示重新连接到JupyterLab终端。也许是这样。但笔记本无法工作。希望v7能解决所有问题。 - Alex
@Alex 如果您的重点在于“打印输出”,就像我更新的那样,它不适用于 JupyterLab。在这种情况下,您可以尝试 Jupyter 的执行 API。但是,如果您只想在关闭选项卡/浏览器后继续运行笔记本(例如一个非常长且缓慢的循环),它是有效的。 - YaOzI

4

我也一直在为这个问题苦苦挣扎。

我的解决方法是将所有日志写入文件,这样当我的浏览器关闭时(确实当大量日志通过浏览器传输时,它也会挂起),我可以通过打开日志文件来查看内核作业进程(日志文件也可以使用Jupyter打开)。

#!/usr/bin/python
import time
import datetime
import logging

logger = logging.getLogger()

def setup_file_logger(log_file):
    hdlr = logging.FileHandler(log_file)
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
    hdlr.setFormatter(formatter)
    logger.addHandler(hdlr) 
    logger.setLevel(logging.INFO)

def log(message):
    #outputs to Jupyter console
    print('{} {}'.format(datetime.datetime.now(), message))
    #outputs to file
    logger.info(message)

setup_file_logger('out.log')

for i in range(10000):
    log('Doing hard work here i=' + str(i))
    log('Taking a nap now...')
    time.sleep(1000)

0

我之前使用 jupyter nbconvert 构建了这个程序,本质上是在后台运行一个笔记本而没有任何 UI:

nohup jupyter nbconvert --ExecutePreprocessor.timeout=-1 --CodeFoldingPreprocessor.remove_folded_code=False --ExecutePreprocessor.allow_errors=True --ExecutePreprocessor.kernel_name=python3 --execute --to notebook --inplace ~/mynotebook.ipynb > ~/stdout.log 2> ~/stderr.log &

  • timeout=-1 表示无超时限制
  • remove_folded_code=False 如果启用了 Codefolding 扩展,则不删除折叠的代码
  • allow_errors=True 忽略错误单元格并继续运行笔记本直到结束
  • kernel_name 如果您有多个内核,请使用 jupyter kernelspec list 进行检查

0
有方法可以将你的笔记本转换成Python脚本。 请参考这里:convert-jupyter-notebook-python
所以你可以简单地转换为脚本,然后运行该脚本。不需要浏览器。

0
如果您已经设置了所有单元格并想定期检查正在打印的内容,以下代码将比%%capture更好。您始终可以在内核忙碌时打开日志文件。
import sys
sys.stdout = open("my_log.txt", "a")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接