在Bash下实现简单的任务并行与排队

637天前 · Linux 使用 · 584次阅读

在没有安装 slurm 等排队系统的 Linux 机器上需要同时排队运行超过CPU核心数目的任务时,可以使用 Linux 中的 “命名管道” 来实现简单的任务并行与排队。

下面给出一个 Bash 脚本范例,Nproc 定义了同时运行的任务数量(不能超过CPU的核心/线程数)
tasks 列表则是需要运行的任务命令,将双引号内的内容替换即可。

Nproc=5    # 可同时运行的最大作业数

#
tasks=(\
"job-1 ..." \
"job-2 ..." \
"job-3 ..." \
"job-4 ..." \
"job-5 ..." \
"job-6 ..." \
"job-7 ..." \
"job-8 ..." \
)

Njob=${#tasks[@]}
echo "we have " $Njob "tasks"


function CMD {        # 测试命令, 随机等待几秒钟
        n=$((RANDOM % 5 + 1))
        echo "Job $1 - running ..."
        #sleep $n
        let "idx = $1 - 1"
        echo $1 
        eval ${tasks[$idx]}
        echo "Job $1 - exiting ..."
}

Pfifo="/tmp/$$.fifo"   # 以PID为名, 防止创建命名管道时与已有文件重名,从而失败
mkfifo $Pfifo          # 创建命名管道
exec 6<>$Pfifo         # 以读写方式打开命名管道, 文件标识符fd为6
                       # fd可取除0, 1, 2,5外0-9中的任意数字
rm -f $Pfifo           # 删除文件, 也可不删除, 不影响后面操作

# 在fd6中放置$Nproc个空行作为令牌
for((i=1; i<=$Nproc; i++)); do
        echo
done >&6

for((i=1; i<=$Njob; i++)); do  # 依次提交作业
        read -u6                   # 领取令牌, 即从fd6中读取行, 每次一行
                               # 对管道,读一行便少一行,每次只能读取一行
                               # 所有行读取完毕, 执行挂起, 直到管道再次有可读行
                               # 因此实现了进程数量控制
        {                          # 要批量执行的命令放在大括号内, 后台运行
                CMD $i && {            # 可使用判断子进程成功与否的语句
                        echo "Job $i finished"
                } || {
                        echo "Job $i error"
                }
                sleep 1     # 暂停1秒,可根据需要适当延长,
                    # 关键点,给系统缓冲时间,达到限制并行进程数量的作用
                echo >&6    # 归还令牌, 即进程结束后,再写入一行,使挂起的循环继续执行
        } &

done

wait                # 等待所有的后台子进程结束
exec 6>&-           # 删除文件标识符

该脚本参考了 Jerkwin 的博客 Bash脚本实现批量作业并行化 一文。

👍 1

none

最后修改于635天前

评论

贴吧 狗头 原神 小黄脸
收起

贴吧

狗头

原神

小黄脸

目录

avatar

伊藤

41

文章数

6

评论数

8

分类