Bash 简单实现 多进程运行 —— 加快for循环执行速度
0x01 背景
在bash中,我们可以通过&来让程序在后台运行。如果在for循环中,每个循环处理的处理可以并行执行,那么将每个循环设置在后台执行可以大大加快运行速度:
#!/bin/bash
for ip in 10.3.8.{1..255};
do
(
ping $ip -c2 &> /dev/null
if [ $? -eq 0 ];
then
echo "$ip up..."
fi
)&
done
wait
echo done
但是,当for循环的次数太多,开启大量的后台进程,如果超过了CPU的核心数,仅仅是调度不同的进程运行,进程中断恢复时的上下文切换也会增加很多损耗。因此,我们需要控制同时执行的后台进程数量。
0x02 实现
思路:设置当前可以并行执行的进程数量,通过$! 记录上一个后台执行程序的PID放入数组中,通过ps -p PID检查数组中的PID就可以知道当前哪些进程退出了,之后便可以创建新的后台进程来执行。
#!/bin/bash
# author: thinkycx
# date: 2019-01-14
# Usage:
# run jobs at the same time with multiple process.
# Permanent-URL: https://gist.github.com/thinkycx/f1350b209733afa71523a9f1ec057c96
parallel(){
nCPU=3 # 同时执行的进程数量
PID=()
for((i=0;i<5;i++)){
# while process number >= nCPU
echo "============================================"
# echo "[*] PID() len: " ${#PID[*]}
echo "[*] PID() content:" ${PID[*]}
# echo "[-] Checking PID() length >= nCPU ?"
while [ ${#PID[*]} -ge $nCPU ] ;
do
for pid in ${PID[*]}; do
ps -p $pid >/dev/null
isQuit=$?
if [ $isQuit -eq 1 ] ; then
PID=(${PID[*]/$pid})
echo "[*] Checking... $pid stops. PID() len: " ${#PID[*]}
fi
done
sleep 1;
done
# echo "[*] After check. " ${PID[*]}
# start new process background
(
echo -e "\\t [x] Job $i start to run..."
sleep 5
echo -e "\\t [x] Job $i done. "
)&
PID[$i]=$! # 向数组中添加上一个运行的后台进程的pid
sleep 1
echo -e "\\t [*] process PID is :" ${PID[$i]}
}
}
parallel
wait
echo "[*] Congratilations. All jobs done! "