Slurm技术问题:如何在不影响任务并行性的前提下等待脚本内步骤完成
首先咱们得先揪出你当前配置里的两个核心问题,这才是导致你遇到麻烦的根源:
1. 为什么CPU利用率只有100%,没有并行跑28个任务?
你在Slurm提交脚本里给每个srun加了--exclusive参数,这个参数的意思是请求独占整个节点。也就是说,你每启动一个srun任务,它会把整个节点占满,其他任务只能等这个任务跑完才能启动。这就导致28个任务其实是串行执行的,自然CPU利用率只有100%左右,完全没有并行起来。
2. 为什么dosomething.sh里的Python脚本没按顺序执行(或出现错误)?
其实默认情况下,shell脚本里顺序写的命令是前一个执行完才会启动下一个的,你最初的dosomething.sh写法是没问题的:
python3 py1.py python3 py2.py python3 py3.py python3 py4.py
你后来加的wait $pid完全是多余的——因为你没有把Python命令放到后台(没加&),$!拿到的是空值,反而可能触发一些奇怪的行为(比如wait空PID会等待所有后台进程,间接影响执行逻辑)。你看到的错误日志大概率不是因为没等待,而是其他问题(比如依赖缺失、参数错误、资源不足等),但咱们先把并行和顺序执行的逻辑理顺。
正确的解决方案
第一步:修改Slurm提交脚本,去掉--exclusive参数
咱们要让28个任务真正并行在同一个节点上,每个任务只占用1个核心资源,不需要独占节点。修改后的提交脚本如下:
#!/bin/bash #SBATCH --nodes=1 #SBATCH --ntasks=28 #SBATCH --ntasks-per-node=28 #SBATCH --mem=4000 # Memory per node (in MB). while read data do # 只需要指定-n 1,不需要--exclusive srun -n 1 dosomething.sh $data & done wait
这里的wait是让提交脚本等待所有后台启动的srun任务都完成,这个是必要的,避免Slurm提前结束整个作业。
第二步:恢复dosomething.sh的简洁写法
回到最初的顺序执行写法就足够保证四个Python脚本依次运行:
#!/bin/bash python3 py1.py python3 py2.py python3 py3.py python3 py4.py
如果某个Python脚本执行失败(比如返回非0状态码),后续的脚本会停止执行。如果你希望哪怕前一个失败,后面的也要继续跑,可以在每个命令前加set +e,或者用python3 py1.py || true这样的写法。
额外注意点
- 如果你每个Python脚本是单线程的,那么28个任务刚好占满节点的28个核心,CPU利用率会接近2800%,符合你的预期。
- 如果Python脚本是多线程的(比如用了numpy、pandas的多线程优化),那你可能需要调整
--ntasks的数量,避免多个任务抢占CPU资源导致性能下降。 - 可以用
sacct命令查看作业的执行状态,确认28个任务是否真的并行运行了。
备注:内容来源于stack exchange,提问作者Marco Seracini

