核心思想:
    1)控制线程的总量
    2)用fifo类型的文件来线程间通信,并使用特殊输出管道号如6和read,文件里的行数代表了可以执行的总量,能读说明还有内容,没内容时就会停住等待。执行一个就读一行,执行完就写一行。
    3)使用 &来实现同时执行代码
    4)wait等待所有子进程执行完。关闭输出管道。
    5)不用fifo也可以用变量控制,循环sleep判断总量,只是没有这么实时。

    1. #!/bin/bash
    2. function my_cmd(){
    3. id=$1
    4. echo start:$id
    5. t=$RANDOM #一个小于32767的随机数
    6. t1=$[t%10]
    7. sleep $t1
    8. echo "random=$t;sleep $t1 s;end:$id"
    9. }
    10. tmp_fifofile="/tmp/$$.fifo"
    11. mkfifo $tmp_fifofile # 新建一个fifo类型的文件(先进先出)
    12. exec 6<>$tmp_fifofile # 将fd6指向fifo类型
    13. rm $tmp_fifofile #删也可以
    14. thread_num=5 # 最大可同时执行线程数量
    15. job_num=20 # 任务总数
    16. #根据线程总数量设置令牌个数
    17. for ((i=0;i<${thread_num};i++));do
    18. echo
    19. done >&6
    20. for ((i=0;i<${job_num};i++));do # 任务数量
    21. # 一个read -u6命令执行一次,就从fd6中减去一个回车符,然后向下执行,
    22. # fd6中没有回车符的时候,就停在这了,从而实现了线程数量控制
    23. read -u6
    24. #可以把具体的需要执行的命令封装成一个函数
    25. {
    26. #echo $i
    27. my_cmd $i
    28. echo >&6 # 当进程结束以后,再向fd6中加上一个回车符,即补上了read -u6减去的那个
    29. } & #并发的关键
    30. done
    31. wait
    32. exec 6>&- # 关闭fd6
    33. 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
    ……(无限循环)