Shell编程多线程并发实践

Tips:正常来说shell是不具备多线程能力的,也就是说shell本身是按顺序进行执行指令的,并不能并发执行。但是可以换个思路,通过遍历+后台执行的方式进行模拟多线程的方式。但是还有个问题就是如何去控制并发数量,比如你要批量往1w台机器上copy一个文件,如果不设置并发数,估计直接就带宽跑满game over了,不过也有对应的解决方案,往下看吧。

并发方案模型

  • 无并发设置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/bin/bash
    echo `date`
    echo "-----------Arvon.top Loop Begin-------------"
    for i in `seq 3`;do
    sleep 10
    echo $i
    echo `date`
    done
    echo "-----------Arvon.top Loop End-------------"
    echo `date`

    输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Wed Aug 2 12:53:25 UTC 2017
    -----------Arvon.top Loop Begin-------------
    1
    Wed Aug 2 12:53:35 UTC 2017
    2
    Wed Aug 2 12:53:45 UTC 2017
    3
    Wed Aug 2 12:53:55 UTC 2017
    -----------Arvon.top Loop End-------------
    Wed Aug 2 12:53:55 UTC 2017
  • 无并发数设置
    Tips:敲黑板,注意wait这个指令,需要在如果需要循环体内所有任务执行完成后再执行其他指令,需要在循坏外紧接着加上

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #!/bin/bash
    echo `date`
    echo "-----------Arvon.top Loop Begin-------------"
    for i in `seq 3`;do
    {
    sleep 10
    echo $i
    echo `date`
    }&
    done
    wait
    echo "-----------Arvon.top Loop End-------------"
    echo `date`

    输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Wed Aug 2 13:04:34 UTC 2017
    -----------Arvon.top Loop Begin-------------
    1
    2
    3
    Wed Aug 2 13:04:44 UTC 2017
    Wed Aug 2 13:04:44 UTC 2017
    Wed Aug 2 13:04:44 UTC 2017
    -----------Arvon.top Loop End-------------
    Wed Aug 2 13:04:44 UTC 2017
  • 有并发数设置
    Tips:这里需要用到一种特殊的文件名称为有名管道(FIFO),这个具体会另写一篇,注意&6和read这些地方

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #!/bin/bash
    server_list=`seq 10`
    thread=3
    # Create FIFO
    tmp_fifofile="/tmp/$$.fifo"
    mkfifo $tmp_fifofile
    exec 6<> $tmp_fifofile
    rm $tmp_fifofile
    for ((i=0;i<$thread;i++)); do
    echo
    done >& 6
    # user operation
    function user_scripts(){
    sleep 10
    echo `date`
    }
    echo `date`
    echo "-----------Arvon.top Loop Begin-------------"
    for i in ${server_list};do
    read -u6
    {
    user_scripts
    echo >&6
    }&
    done <&6
    wait
    exec 6>&-
    echo "-----------Arvon.top Loop End-------------"
    echo `date`

    输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Wed Aug 2 14:12:03 UTC 2017
    -----------Arvon.top Loop Begin-------------
    Wed Aug 2 14:12:13 UTC 2017
    Wed Aug 2 14:12:13 UTC 2017
    Wed Aug 2 14:12:13 UTC 2017
    Wed Aug 2 14:12:23 UTC 2017
    Wed Aug 2 14:12:23 UTC 2017
    Wed Aug 2 14:12:23 UTC 2017
    Wed Aug 2 14:12:33 UTC 2017
    Wed Aug 2 14:12:33 UTC 2017
    Wed Aug 2 14:12:33 UTC 2017
    Wed Aug 2 14:12:43 UTC 2017
    -----------Arvon.top Loop End-------------
    Wed Aug 2 14:12:43 UTC 2017

实战小栗子

  • 例子1:需要

    • 本机上进行并行运行脚本
    • 每次并行需要不同的配置文件

    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #!/bin/bash
    # cat server.csv | grep gid > confd/
    for i in `cat server.csv | egrep -v "gid"`;do
    sid=`echo $i |awk -F',' '{print $2}'`
    cat server.csv | grep gid > confd/${sid}_server.csv
    echo $i >> confd/${sid}_server.csv
    {
    echo "./tool_refresh_gs -save -config confd/${sid}_server.csv -out ${sid}"
    #./tool_refresh_gs -save -config confd/${sid}_server.csv -out ${sid}
    }&
    done
    wait

不错的

写的很不错