并行化for循环


9

我想并行化for以下代码的循环。这个怎么做?

#!/bin/bash
N=$1 
n=$2
for (( i=1; i<=$N; i++ )); do
  min=100000000000000  //set min to some garbage value
  for (( j=1; j<=$n; j++ )); do
    val=$(/path/to/a.out)
    val2=`echo $val | bc`  

      if (( $val2 < $min )); then
        min=$val2; 
      fi
  done
  arr=("${arr[@]}" "$min")
done


Answers:


10
#!/bin/bash
# set -x # debug version
N=${1:-123}
n=${2:-45}
workers=${workers:-${3:-10}}
((workers < 1)) && ((workers = 1))
((workers > 20)) && ((workers = 20))

((min=100000000000000))  #set min to some garbage value

work() {
  for i in ${*}; do
    for (( j=1; j<=${n}; j++ )); do
      val=$(/path/to/a.out)
      val2=$(echo ${val} | bc)
      (( val2 < min )) && (( min = val2 ));
    done
    echo ${min}
    # # debug version
    # echo ${i} ${j} ${min}
  done
}

# --
arr=($(
  seq ${N} | xargs -n$[N/workers + 1] | while read i; do
    work ${i} &
  done
  wait
))
echo ${arr[*]}
# --

# # debug version
# seq ${N} | xargs -t -n$[N/workers + 1] | while read i; do
#  work ${i} &
# done
# wait

生成参数化的进程数量时,请始终使用worker,并限制可以生成的最大worker数量

xargs -n | while read 是批量迭代列表的一种简单方法。

  • seq 创建一个从1到N的数字列表。
  • xargs -n 将列表分为N / workers + 1个批次。
    • 例如N = 100 worker = 10将产生10行,最多11个数字(从1到100)。
  • while read i 读取数字的每一行。
  • work ${i} &只是work${i}一批数字调用函数。

为了调试,我添加了注释掉的调试代码。只需将其替换为echo调试版本,并将其之间的代码# --替换为其调试版本,就可以看到它是如何批量运行的。取消注释set -x以获取更详细的调试输出,您可能希望将其重定向到文件。

只需使用不同的参数运行调试版本以查看其运行方式:

parallel.sh 223 5 1
parallel.sh 223 5 5
parallel.sh 223 5 10
parallel.sh 223 5 20

免责声明:此代码不会min在辅助进程之间同步值。获得最小值并不是一件可怕的事情。这可能会做:

parallel.sh 223 5 20 | tr ' ' '\n' | sort -n | head -1

或者只是将其添加到脚本本身:

echo ${arr[*]} | tr ' ' '\n' | sort -n | head -1

你能解释一下代码吗?我不清楚您如何在这里使用工作线程。
里查德·威廉姆斯

@prasenjit完成。希望对您有所帮助。
nicerobot 2011年

8

使用GNU并行:

#!/bin/bash

N=$1
n=$2

arr=($(
# Generate all combinations of 1..n and 1..N
parallel -k --tag /path/to/a.out {1} {2} '|' bc :::: <(seq $N) <(seq $n) |
  perl -ane 'BEGIN{$min=1e30} $last||=$F[0]; if($F[0] != $last) {print $min,"\n";$min=1e30;$last=$F[0]} $min = $F[2]<$min ? $F[2] : $min; END {print $min,"\n"}'
))
echo ${arr[*]}

这将/path/to/a.out在每个cpu上运行。输出将类似于:

1 1 19269
1 2 6158
1 3 2794
1 4 25104
2 1 13160
2 2 32683
2 3 12535
2 4 15197
3 1 8228
3 2 7673
3 3 8428
3 4 24463

perl脚本查看第一列,并在第三列中找到具有相同第一列的最小值。

您可以通过以下方法简单地安装GNU Parallel:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel

观看介绍性视频以了解更多信息:https : //www.youtube.com/playlist?list=PL284C9FF2488BC6D1


上一段中的链接链接到一个Facebook查找页面,该页面告诉访问者他赢得了独家礼物(广告或欺诈)。没有视频。您应该将其删除。
马可(Marco)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.