易于并行化

时间:2008-11-11 19:40:06

标签: bash parallel-processing

我经常发现自己编写简单的for循环来对许多文件执行操作,例如:

for i in `find . | grep ".xml$"`; do bzip2 $i; done

似乎有点令人沮丧的是,在我的4核机器上只使用了一个核心..有一种简单的方法可以为我的shell脚本添加并行性吗?

编辑:为我的问题介绍更多的背景,对不起,我开始时并不是更清楚!

我经常想在合理大小的数据集(通常在100到10,000之间)上运行简单(ish)脚本,例如绘制图形,压缩或解压缩,或运行某些程序。我用来解决这些问题的脚本看起来像上面那样,但可能有不同的命令,甚至是一系列要执行的命令。

例如,刚才我正在运行:

for i in `find . | grep ".xml.bz2$"`; do find_graph -build_graph $i.graph $i; done

所以我的问题绝不是特定于bzip的! (虽然并行bzip确实看起来很酷,但我打算将来使用它。)

8 个答案:

答案 0 :(得分:14)

解决方案:使用xargs并行运行(不要忘记-n选项!)

find -name \*.xml -print0 | xargs -0 -n 1 -P 3 bzip2

答案 1 :(得分:6)

This perl program可以很好地满足您的需求,您只需这样做:

runN -n 4 bzip2 `find . | grep ".xml$"`

答案 2 :(得分:4)

gnu make有一个很好的并行功能(例如-j 5)可以在你的情况下工作。创建一个Makefile

%.xml.bz2 : %.xml


all: $(patsubt %.xml,%xml.bz2,$(shell find . -name '*.xml') ) 

然后做一个

nice make -j 5

用一些数字替换'5',可能比CPU的数量多1。您可能希望做到“好”,以防万一其他人想要在您使用机器时使用该机器。

答案 3 :(得分:2)

一般问题的答案很难,因为它取决于您要并行化的事物的细节。 另一方面,为了这个特定的目的,你应该使用pbzip2而不是普通的bzip2(可能已经安装了pbzip2或者至少在存储库或你的发行版中)。有关详细信息,请参阅此处:http://compression.ca/pbzip2/

答案 4 :(得分:2)

我发现这种操作适得其反。原因是在读/写时间越长的同时访问磁盘的进程越多,因此最终结果会在更长的时间内结束。无论你有多少核心,这里的瓶颈都不会是CPU问题。

你有没有在同一台高清硬盘上同时执行过两个简单的大文件副本?我通常会更快地复制一个而不是另一个。

我知道这个任务涉及一些CPU功率(bzip2要求压缩方法),但是在走向“挑战”路径之前尝试测量第一个CPU负载,我们所有技术人员往往选择的频率远远超过需要。

答案 5 :(得分:2)

我为bash做了类似的事情。对于一次性,并行make技巧可能要快很多,但是这里是在bash中实现这样的东西的主要代码部分,你需要为你的目的修改它:

#!/bin/bash

# Replace NNN with the number of loops you want to run through
# and CMD with the command you want to parallel-ize.

set -m

nodes=`grep processor /proc/cpuinfo | wc -l`
job=($(yes 0 | head -n $nodes | tr '\n' ' '))

isin()
{
  local v=$1

  shift 1
  while (( $# > 0 ))
  do
    if [ $v = $1 ]; then return 0; fi
    shift 1
  done
  return 1
}

dowait()
{
  while true
  do
    nj=( $(jobs -p) )
    if (( ${#nj[@]} < nodes ))
    then
      for (( o=0; o<nodes; o++ ))
      do
        if ! isin ${job[$o]} ${nj[*]}; then let job[o]=0; fi
      done
      return;
    fi
    sleep 1
  done
}

let x=0
while (( x < NNN ))
do
  for (( o=0; o<nodes; o++ ))
  do
    if (( job[o] == 0 )); then break; fi
  done

  if (( o == nodes )); then
    dowait;
    continue;
  fi

  CMD &
  let job[o]=$!

  let x++
done

wait

答案 6 :(得分:1)

我认为你可以到以下

for i in `find . | grep ".xml$"`; do bzip2 $i&; done

但是,由于你立即拥有文件,这会分散许多进程,而不是一次只运行四个进程。

答案 7 :(得分:1)

如果你今天必须解决问题,你可能会使用像GNU Parallel这样的工具(除非你的任务有专门的并行工具,如pbzip2):

find . | grep ".xml$" | parallel bzip2

了解更多信息: