核心思想:
1)控制线程的总量
2)用fifo类型的文件来线程间通信,并使用特殊输出管道号如6和read,文件里的行数代表了可以执行的总量,能读说明还有内容,没内容时就会停住等待。执行一个就读一行,执行完就写一行。
3)使用 &来实现同时执行代码
4)wait等待所有子进程执行完。关闭输出管道。
5)不用fifo也可以用变量控制,循环sleep判断总量,只是没有这么实时。
#!/bin/bash
function my_cmd(){
id=$1
echo start:$id
t=$RANDOM #一个小于32767的随机数
t1=$[t%10]
sleep $t1
echo "random=$t;sleep $t1 s;end:$id"
}
tmp_fifofile="/tmp/$$.fifo"
mkfifo $tmp_fifofile # 新建一个fifo类型的文件(先进先出)
exec 6<>$tmp_fifofile # 将fd6指向fifo类型
rm $tmp_fifofile #删也可以
thread_num=5 # 最大可同时执行线程数量
job_num=20 # 任务总数
#根据线程总数量设置令牌个数
for ((i=0;i<${thread_num};i++));do
echo
done >&6
for ((i=0;i<${job_num};i++));do # 任务数量
# 一个read -u6命令执行一次,就从fd6中减去一个回车符,然后向下执行,
# fd6中没有回车符的时候,就停在这了,从而实现了线程数量控制
read -u6
#可以把具体的需要执行的命令封装成一个函数
{
#echo $i
my_cmd $i
echo >&6 # 当进程结束以后,再向fd6中加上一个回车符,即补上了read -u6减去的那个
} & #并发的关键
done
wait
exec 6>&- # 关闭fd6
echo "over"
参考:https://www.cnblogs.com/xudong-bupt/p/6079849.html ,注意里面有错误。echo >&6的位置要在异步的{}里面。
以下是一个错误示范,子线程不能改变父线程的变量running_num,从而无法实现总量控制:
#!/bin/bash
function my_cmd(){
id=$1
t=$RANDOM #一个小于32767的随机数
t1=$[t%10+5]
echo start:$id,sleep $t1
sleep $t1
echo "end:$id"
}
thread_num=5 # 最大可同时执行线程数量
job_num=20 # 任务总数
running_num=0 # 正在运行的任务
for ((i=0;i<${job_num};i++));do # 任务数量
while ( true );do
echo index=$i,running_num=$running_num
if ( [ ${running_num} -lt ${thread_num} ] );then
running_num=`expr $running_num + 1`
#可以把具体的需要执行的命令封装成一个函数
{
id=$i
echo id=$id,running_num=$running_num
my_cmd $id
running_num=`expr $running_num - 1`
echo id=$id,running_num=$running_num
} & #并发的关键
break
else
echo -n "."
sleep 1;
fi
done;
done
wait
echo "---over---"
输出:
$ sh test.sh
index=0,running_num=0
id=0,running_num=1
start:0,sleep 14
index=1,running_num=1
id=1,running_num=2
start:1,sleep 13
index=2,running_num=2
id=2,running_num=3
start:2,sleep 6
index=3,running_num=3
id=3,running_num=4
start:3,sleep 10
index=4,running_num=4
id=4,running_num=5
start:4,sleep 13
index=5,running_num=5
.index=5,running_num=5
.index=5,running_num=5
.index=5,running_num=5
.index=5,running_num=5
.index=5,running_num=5
.end:2
id=2,running_num=2
index=5,running_num=5
.index=5,running_num=5
.index=5,running_num=5
.end:3
index=5,running_num=5
.id=3,running_num=3
index=5,running_num=5
.index=5,running_num=5
.end:1
id=1,running_num=1
end:4
id=4,running_num=4
index=5,running_num=5
.end:0
id=0,running_num=0
index=5,running_num=5
.index=5,running_num=5
.index=5,running_num=5
.index=5,running_num=5
.index=5,running_num=5
……(无限循环)