1

我正在尝试使用 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
.
.
.
4

4 回答 4

2

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

于 2012-08-20T12:13:09.310 回答
0

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

于 2012-08-20T10:38:11.710 回答
0

根据 a 制定您的脚本,makefile并通过Parallel Executionmake -j N对其进行整理。

于 2012-08-20T15:01:49.100 回答
0

首先,我将给您一个精简的示例,说明我在几个 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
于 2013-08-20T20:01:24.513 回答