代码之家  ›  专栏  ›  技术社区  ›  Chris Jefferson

简单并行化

  •  6
  • Chris Jefferson  · 技术社区  · 16 年前

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

    在我的4核机器上,只有一个核被使用,这似乎有点令人沮丧。。有没有一种简单的方法可以将并行性添加到shell脚本中?

    我经常希望在大小合理的数据集(通常在100到10000之间)上运行简单(ish)脚本,例如绘制图形、压缩或解压缩,或者运行一些程序。我用于解决此类问题的脚本与上面的脚本类似,但可能有不同的命令,甚至可能有一系列要执行的命令。

    例如,刚才我正在跑步:

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

    8 回复  |  直到 16 年前
        1
  •  14
  •   Johannes Schaub - litb    16 年前

    :使用 xargs -n 选项!)

    find -name \*.xml -print0 | xargs -0 -n 1 -P 3 bzip2
    
        2
  •  6
  •   Peter Crabtree    16 年前

    This perl program 非常适合您的需要,您可以这样做:

    runN -n 4 bzip2 `find . | grep ".xml$"`
    
        3
  •  4
  •   David Nehme    16 年前

    GNUMake有一个很好的并行特性(例如,-j5),可以在您的情况下使用。创建一个Makefile

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

    然后做一个测试

    nice make -j 5
    

    将“5”替换为某个数字,可能比CPU的数量多1个。你可能想做的'好'这只是为了防止别人想使用机器,而你在它。

        4
  •  2
  •   Davide    16 年前

    另一方面,出于这个特定目的,您应该使用pbzip2而不是普通的bzip2(pbzip2可能已经安装,或者至少已经安装在存储库或发行版中)。详情请参见此处: http://compression.ca/pbzip2/

        5
  •  2
  •   Evan Teran    16 年前

    我觉得这种做法适得其反。原因是,同时访问磁盘的进程越多,读/写时间就越长,因此最终结果的结束时间就越长。这里的瓶颈不会是CPU问题,不管您有多少个内核。

    我知道这项任务涉及到一些CPU能力(bzip2是一种要求很高的压缩方法),但在走“具有挑战性”的道路之前,请尝试测量第一个CPU负载,我们所有技术人员都倾向于选择比需要更多的路径。

        6
  •  2
  •   Steve Baker    16 年前

    我为bash做了这样的事。parallel 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
    
        7
  •  1
  •   Tom Ritter    16 年前

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

        8
  •  1
  •   Ole Tange    10 年前

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

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