【问题标题】:limiting number of concurrent processes in a bash script限制 bash 脚本中的并发进程数
【发布时间】:2012-08-20 10:35:48
【问题描述】:

我正在尝试使用 bash 脚本并行执行多项工作。这些作业是内存密集型的,所以我需要控制一次启动的数量。我所拥有的如下,它可以广泛使用,但有时延迟循环不知道刚刚启动的作业,因此启动了几个额外的作业,导致系统内存不足。

在延迟循环中的 while 语句之前添加一个 sleep 可以减少这个问题,但并不能完全消除它。任何人都知道治愈这种情况的方法。如果相关的话,我正在 Solaris 上运行。

#!/bin/bash
delay(){
while [ 8 -le $(ps -ef |grep  myjob |wc -l) ]
do
sleep 1
done
}

./myjob -params1 &
delay
./myjob -params2 &
delay
./myjob -params3 &
delay
./myjob -params4 &
delay
.
.
.

【问题讨论】:

标签: bash solaris


【解决方案1】:

GNU parallel 实用程序 http://www.gnu.org/software/parallel/ 可能是正确的工具,因为可以说它比 xargs 更易于使用

【讨论】:

    【解决方案2】:

    首先,我将给您一个精简的示例,说明我在几个 linux 脚本中所做的事情。这应该在 solaris 上工作,但我目前没有任何系统可以测试。我修改了一些使用 /proc 的东西,所以如果有什么不起作用,请告诉我。

    #!/bin/bash
    
    # set the max # of threads
    max_threads=4
    # set the max system load
    max_load=4
    
    print_jobs(){
    # flush finished jobs messages
      jobs > /dev/null
      for x in $(jobs -p) ; do
       # print all jobs
        echo "$x"
      done
    }
    
    job_count(){
      cnt=$(print_jobs $1)
      if [ -n "$cnt" ]; then
        wc -l <<< "$cnt"
      else
        echo 0
      fi
    }
    
    cur_load(){
      # get the 1 minute load average integer
      uptime |sed 's/.*load average[s]*:[[:space:]]*\([^.]*\)\..*/\1/g'
    }
    
    
    main_function(){
     # get current job count and load
      jcnow=$(job_count)
      loadnow=$(cur_load)
    
     # first, enter a loop waiting for load/threads to be below thresholds
      while [ $loadnow -ge $max_load ] || [ $jcnow -ge $max_threads ]; do
        if ! [ $firstout ]; then
          echo "entering sleep loop. load: $loadnow, threads: $jcnow"
          st=$(date +%s)
          local firstout=true
        else
          now=$(date +%s)
         # if it's been 5 minutes, echo again:
          if [ $(($now - $st)) -ge 300 ]; then
            echo "still sleeping. load: $loadnow, threads: $jcnow"
            st=$(date +%s)
          fi
        fi
        sleep 5s
    
       # refresh these variables for loop
        loadnow=$(cur_load)
        jcnow=$(job_count)
      unset firstout
      done
    
      ( ./myjob $@ ) &
    }
    
    # do some actual work
    for jobparams in "params1" "params2" "params3" "params4" "params5" "params6" "params7" ; do
       main_function $jobparams
    done
    
    wait
    

    几个注意事项:

    • 您应该捕获信号,以便您可以终止子进程。我不知道如何在 solaris 中执行此操作,但这适用于 linux:trap 'echo "exiting" ; rm -f $lockfile ; kill 0 ; exit' INT TERM EXIT
    • 如果在作业已经运行的情况下负载攀升,则无法降低速度

    如果您根本不关心负载,这可以更简单一些:

    #!/bin/bash
    
    # set the max # of threads
    max_threads=4
    
    print_jobs(){
    # flush finished jobs messages
      jobs > /dev/null
      for x in $(jobs -p) ; do
       # print all jobs
        echo "$x"
      done
    }
    
    job_count(){
      cnt=$(print_jobs $1)
      if [ -n "$cnt" ]; then
        wc -l <<< "$cnt"
      else
        echo 0
      fi
    }
    
    main_function(){
     # get current job count
      jcnow=$(job_count)
    
     # first, enter a loop waiting for threads to be below thresholds
      while [ $jcnow -ge $max_threads ]; do
        if ! [ $firstout ]; then
          echo "entering sleep loop. threads: $jcnow"
          st=$(date +%s)
          local firstout=true
        else
          now=$(date +%s)
         # if it's been 5 minutes, echo again:
          if [ $(($now - $st)) -ge 300 ]; then
            echo "still sleeping. threads: $jcnow"
            st=$(date +%s)
          fi
        fi
        sleep 5s
    
       # refresh these variables for loop
        jcnow=$(job_count)
      unset firstout
      done
    
    
      ( ./myjob $@ ) &
    }
    
    # do some actual work
    for jobparams in "params1" "params2" "params3" "params4" "params5" "params6" "params7" ; do
       main_function $jobparams
    done
    
    wait
    

    【讨论】:

      【解决方案3】:

      使用xargs 执行此操作。传递-n 1 表示每个作业一个参数,并使用--max-jobs 参数指定并发进程数。

      【讨论】:

        【解决方案4】:

        根据makefile 制定您的脚本,并让make -j N 通过Parallel Execution 对其进行排序。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-04-12
          • 1970-01-01
          • 2016-12-04
          • 1970-01-01
          • 1970-01-01
          • 2010-12-05
          • 1970-01-01
          相关资源
          最近更新 更多