核心是通过日志文件的文件句柄关联后台进程 PID,再通过 PID 终止进程。
bash
1. 挂后台运行
nohup nnUNetv2_train 1 3d_fullres 0 -p nnUNetResEncUNetMPlans -tr RSNA2025Trainer_moreDAv6_SkeletonRecallW3TverskyBeta07_with_test > train_aneurysm_model3_0.log 2>&1
2. 取消后台运行代码
lsof | grep train_aneurysm_model3_0.log
kill 12345
一、先搞懂:nohup 后台运行命令的本质
我挂在后台的命令是:
bash
nohup nnUNetv2_train 1 3d_fullres 0 -p nnUNetResEncUNetMPlans -tr RSNA2025Trainer_moreDAv6_SkeletonRecallW3TverskyBeta07_with_test > train_aneurysm_model3_0.log 2>&1
这行命令的作用是让训练程序脱离当前终端后台运行,且关闭终端后进程不终止,关键拆解:
- nohup:全称no hang up(不挂断),作用是解除进程与当前终端的关联。默认情况下,终端是进程的「父进程」,关闭终端会给子进程发SIGHUP(挂断信号)导致进程终止;nohup会忽略SIGHUP信号,让进程被系统的init/systemd进程接管,成为「孤儿进程」后继续后台运行。
-
train_aneurysm_model3_0.log:标准输出(stdout,文件描述符 1)重定向,程序运行的正常打印信息(比如训练日志、进度)不再输出到终端,而是写入指定日志文件。
- 2>&1:标准错误(stderr,文件描述符 2)重定向到标准输出,程序的错误信息(比如报错、警告)也会跟着标准输出一起写入同一个日志文件,实现「正常日志 + 错误日志」合并记录。
- 整个命令的进程关系:运行后会生成一个主进程(就是nnUNetv2_train的执行进程),这个进程会持有日志文件的「文件句柄」(系统为打开的文件分配的唯一标识),只要进程没终止,这个文件句柄就会一直存在。
二、核心步骤 1:lsof | grep 日志文件 ------ 从文件找进程的底层原理
bash
lsof | grep train_aneurysm_model3_0.log
是反向查找进程的关键,先解读两个命令的核心作用,再讲组合后的关联逻辑。
1. lsof 命令:List Open Files(列出系统中所有打开的文件)
这是 Linux/Unix 下的核心工具,其设计基础是:Linux 中「一切皆文件」 ------ 普通文件、目录、网络套接字、管道、设备,甚至进程的文件描述符,都会被系统当作「文件」管理。
任何进程只要打开了某个文件(比如你的训练进程写入日志文件,本质就是「打开文件并持续写入」),系统就会在内核中记录这个关联关系,包含以下关键信息:
- PID:打开文件的进程 ID(我们要杀进程的核心标识);
- USER:运行该进程的用户;
- COMMAND:进程对应的命令(比如我们的nnUNetv2_train);
- FD:文件描述符(stdout=1、stderr=2、写模式 = w 等);
- TYPE:文件类型(普通文件 = REG);
- NAME:打开的文件路径 / 名称(我们需要打开的日志文件名)。

注意:lsof 不加参数时,会列出系统所有进程打开的所有文件,结果非常多,因此需要和grep组合过滤。
2. grep 命令:全局正则匹配(过滤指定字符串)
grep train_aneurysm_model3_0.log的作用是:从lsof的输出结果中,只保留包含日志文件名的行 ------ 因为只有我们的训练进程会打开这个日志文件(其他进程不会访问这个自定义日志文件),因此过滤后的结果就是与该日志文件关联的所有进程。
底层核心逻辑:训练进程通过nohup后台运行时,会持续打开日志文件并持有其文件句柄(因为要不断写入训练日志),lsof能捕获到这个「进程 - 打开的文件」的内核关联记录,再通过grep过滤出目标进程,实现从日志文件反向找到其对应的进程 PID。
三、核心步骤 2:杀掉进程 ------ 向 PID 发送终止信号
通过lsof | grep拿到 PID 后,你需要执行杀进程命令(常用kill或kill -9),本质是向指定 PID 的进程发送「信号」,系统根据信号类型执行对应的操作,核心分两种常用方式:
1. 优雅终止:kill [PID](默认发送 SIGTERM 信号,信号编号 15)
命令示例:kill 12345(12345 是你拿到的 PID)
- 作用:向进程发送友好的终止信号,进程收到后会执行「清理操作」(比如保存训练进度、关闭打开的文件、释放内存 / 显卡资源),再正常退出;
- 适用场景:希望保留训练进度,后续可以重新加载继续训练的情况(nnUNet 训练会自动保存检查点,优雅终止后检查点不会损坏)。
2. 强制终止:kill -9 [PID](发送 SIGKILL 信号,信号编号 9)
命令示例:kill -9 12345
- 作用:向进程发送强制终止信号,这个信号无法被进程忽略或捕获,系统会直接从内核层面杀死进程,进程没有任何机会执行清理操作;
- 适用场景:优雅终止(kill PID)后进程仍未退出(比如训练进程卡死),或确认不需要保留当前进度的情况(注意:可能导致最新的检查点损坏)。
补充:批量杀进程(如果有子进程)
少数情况下,nnUNetv2_train会生成子进程(比如多卡训练的子进程),此时lsof会列出多个 PID,可通过管道批量杀死:
bash
bash
# 直接强制杀死所有关联该日志文件的进程
lsof -t train_aneurysm_model3_0.log | xargs kill -9