shell 并行执行

shell 并行执行

串行改为并行

这是常规串行例子

>  for i in `seq 1 10`
do
    sleep 1; echo $i
done 

这是一个迭代次数为10的循环,每一个循环都会等待 1 秒,执行总时长约等于 10 秒。sleep 1 会阻塞循环,只有 sleep 1 执行结果,才会进入下一循环,这是典型的串行模式

shell 提供了一种把命令提交到后台任务队列的机制,即使用 命令 & 将命令控制权交到后台并立即返回执行下个任务。

>  for i in `seq 1 10`
do
    sleep 1 &; echo $i
done

并行-等待模式

上面将串行循环改为并行循环的例子,并没考虑这样的情况。

>  for i in `seq 1 10`
do
    sleep 1 &; echo $i
done
echo "all weakup"

这个例子要求在 for 循环中的所有命令(sleep 1)都执行完之后,打印 “all weakup”。如果按照这段脚本,发现情况并不是这样的,因为 for 循环不会等待 sleep 命令执行结束后才结束,而是把命令提交给系统后自己就退出了,进而还没有1个 sleep 执行完毕之前,“all weakup” 就已经打印了。

为了达到题目要求,需要在 echo "all weakup" 命令之前,加上 wait命令,意为等待上面所有 & 作用过的后台任务执行结束后才继续往下。

>  for i in `seq 1 10`
do
    sleep 1 &; echo $i
done
wait
echo "all weakup"

利用命名管道来做任务队列

大致原理是创建一个 FIFO 命名管道来做为队列,先放进一定量的字符到这个管道做为信号。然后在一个 for 循环中,每循环一次,从管道中读取一个字符信号,提交一个后台任务,并往这个管道中追加一个字符信号,保持管道中的字符信号数量。

是不是很像golang 中的 chan。没有接触过命名管理、文件描述符等概念的,可能会比较难以理解下面示例中的部分细节。

_fifofile="$$.fifo"
mkfifo $_fifofile     # 创建一个FIFO类型的文件
exec 6<>$_fifofile    # 将文件描述符6写入 FIFO 管道, 这里6也可以是其它数字
rm $_fifofile         # 删也可以,

degree=4  # 定义并行度

#根据并行度设置信号个数
#事实上是在fd6中放置了$degree个回车符
for ((i=0;i<${degree};i++));do
    echo
done >&6

for i in `seq 1 20` # 循环20次
do
    # 从管道中读取(消费掉)一个字符信号
    # 当FD6中没有回车符时,停止,实现并行度控制
    read -u6
    {
        sleep 1  # 实际任务的命令
        echo $i
        echo >&6 # 当进程结束以后,再向管道追加一个信号,保持管道中的信号总数量
    } &
done

wait # 等待所有任务结束

exec 6>&- # 关闭管道

文档转自

如何在 shell 中实现并行执行

posted @ 2023-02-09 12:49  liwenchao1995  阅读(193)  评论(0编辑  收藏  举报