在阿里云搭建了一个远程Jupyter Notebook服务,但是每次关闭了jupyter服务的终端窗口或者ssh自动断开连接的时候,会将jupyter服务挂断。

这样的场景我们经常碰见,折腾了一下,发现可以使用Linux中nohup命令来守卫程序,保证程序不受本地关闭终端窗口/网络断开连接的干扰。

在讲nohup之前,先介绍一下Linux中前后台任务的知识。

前台任务

前台任务是独占命令行窗口的任务,只有运行完了或者手动中止该任务,才能执行其他命令。比如我们开了一个jupyter notebook, 这个命令行就被独占了,无法执行其他命令,除非关闭了jupyter,命令行才可以输入其他命令。

后台任务

与前台任务相对应,后台任务在运行的时候,并不需要与用户交互,它们通常在不打扰用户其它工作的时候默默地执行。使shell可以继续响应用户的输入。后台任务继承当前会话的标准输出(stdout)和标准错误(stderr)。因此,后台任务的所有输出依然会同步地在命令行下显示。不再继承当前session的标准输入(stdin),你无法向这个任务输入指令了。如果它试图读取标准输入,就会暂停执行。

可以看出,”后台任务”与”前台任务”的本质区别只有一个:是否继承标准输入

前台任务切换为后台任务

•启动时以后台任务启动,只需要在原来的命令后面加上&,启动的进程就会变为后台进程。

# root @ WeideMac-Pro in ~ [14:15:51] C:130# 在后台运行一个Python  $ python &[2] 12162# root @ WeideMac-Pro in ~ [14:15:56]   $ Python3.6.1|Anaconda custom (x86_64)| (default, May112017, 13:04:09) [GCC 4.2.1CompatibleApple LLVM 6.0(clang-600.0.57)] on darwinType"help", "copyright", "credits"or"license"for more information.[2]  + 12162 suspended (tty output)  python# root @ WeideMac-Pro in ~ [14:15:56] # 这时候发现命令行可以继续执行其他命令了,使用fg命令,将最后一个后台任务切换为前台任务  $ fg[2]  - 12162 continued  python>>> print('Hello')Hello>>>

•将正在运行的前台任务切换为后台任务,先ctrl+z将前台程序挂起, 然后执行bg命令继续运行。

# root @ WeideMac-Pro in ~ [14:20:10] # 在前台运行一个Python  $ pythonPython3.6.1|Anaconda custom (x86_64)| (default, May112017, 13:04:09) [GCC 4.2.1CompatibleApple LLVM 6.0(clang-600.0.57)] on darwinType"help", "copyright", "credits"or"license"for more information.>>> ^Z[1]  + 12248 suspended  python(base) # root @ WeideMac-Pro in ~ [14:20:28] C:146# bg命令,让后台任务继续执行  $ bg[1]  + 12248 continued  python[1]  + 12248 suspended (tty output)  python

将一个程序变为后台任务并不能达到退出命令行后继续运行的效果,这是因为前面的那些前台和后台进程都算做是我们打开那个命令行的子进程,如果我们关掉了命令行,系统将向这些子进程发送一个称为“SIGHUP”的信号,子进程收到信号后就会关闭。因此,只需要让子进程忽略SIGHUP信号,就能实现关闭命令行窗口后程序继续运行了。

什么是nohup?

nohup 全称:no hang up(不挂起)。可以将程序以忽略挂起信号的方式运行起来,被运行的程序的输出信息将不会显示到终端

基本用法
nohup Command[ Arg… ] [ & ]

nohup Command [Arg...] [ &] 最后的" &":表示后台运行,不霸占交互命令行

如果不将 nohup 命令的输出重定向,输出将附加到当前目录的 nohup.out 文件中。

如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。

如果没有文件能创建或打开以用于追加,那么 Command 参数指定的命令不可调用。

示例:

nohup jupyter notebook &

运行上面的命令,就会以后台任务运行jupyter,并且忽略挂起信号,即使关闭了命令行,我们依然可以正常访问 jupyter notebook。

如何kill后台任务

既然程序可以放在后台运行,那我们该如何关掉后台任务呢?要关闭后台任务,关键是要找到后台任务的进程ID, 然后通过kill -9 [id]来杀死进程。这里提供两种方法:

•如果创建任务的终端窗口没有被关掉,可以使用jobs -l查看进程ID

# root @ WeideMac-Pro in ~ [15:22:22]   $ pythonPython3.6.1|Anaconda custom (x86_64)| (default, May112017, 13:04:09) [GCC 4.2.1CompatibleApple LLVM 6.0(clang-600.0.57)] on darwinType"help", "copyright", "credits"or"license"for more information.>>> ^Z[1]  + 13089 suspended  python# root @ WeideMac-Pro in ~ [15:22:34]   $ jobs -l[1]  + 13089 suspended  python# root @ WeideMac-Pro in ~ [15:22:47]   $ kill -913089[1]  + 13089 killed     python

•如果命令行被关掉了,我们jobs命令是找不到我们的后台任务的,因为每个后台任务都是和命令行关联在一起,这里我们可以使用ps命令:

# root @ WeideMac-Pro in ~ [15:33:30]   $ python &                         [1] 13434  # root @ WeideMac-Pro in ~ [15:33:39]   $ Python 3.6.1 |Anaconda custom (x86_64)| (default, May 11 2017, 13:04:09)   [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin  Type "help", "copyright", "credits" or "license" for more information.  [1]  + 13434 suspended (tty output)  python  # root @ WeideMac-Pro in ~ [15:33:39]   $ ps -ef|grep python|grep -v grep    501 13434 12860   0  3:33下午 ttys000    0:00.04 python  # root @ WeideMac-Pro in ~ [15:33:42]   $ kill -9 13434  [1]  + 13434 killed     python