2008-11-11 54 views
6

我经常发现自己写一个简单的for循环来进行操作的许多文件,例如:易于并行化

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

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

编辑:为了引进更多的情况下,以我的问题,对不起,我是不是更清晰下手!

我经常要运行简单的(ISH)脚本,例如图的曲线图,压缩或解压缩,或者在合理规模的数据集运行一些程序,(通常是100和10000之间)。我用来解决这些问题的脚本看起来像上面的脚本,但可能有不同的命令,甚至是一系列要执行的命令。

例如,刚才我运行:

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

所以我的问题是不以任何方式的bZIP具体! (虽然并行bzip看起来很酷,但我打算将来使用它)。

+0

只是一个说明,但你可以使用xargs不必写这样一个循环: 找到。 | grep“.xml.bz2 $”| xargs -n1 bzip2 (-n1表示只传递每个bzip 1参数,默认情况下xargs将所有参数传递给一个进程)。不幸的是,xargs连续进行每个过程。 – 2008-11-11 20:29:34

+0

你应该做`find。 -name \ *。xml.bz2`而不是`find。 | grep“.xml.bz2 $”` - 这正是发现的目的! (另外,你的regex会匹配foozxmlzbz这样的文件名,但这是一个不同而又不重要的问题)。 – 2008-11-11 20:42:58

+0

等待Evan,xargs对于我来说有一个标记为“-P”的参数,对于进程数量! So: 找不到。 | grep“.xml.bz2 $”| xargs -n1 -P3 bzip2 做我想要的 xargs有多长时间? – 2008-11-11 21:50:59

回答

1

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

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

要了解更多信息:

1

我认为你可以到以下

​​

但是当你有即时的文件,是不是最优的,因为就在同时运行四个过程,将分拆然而许多过程。

+0

这对于小型工作是可以的,但我在大约5,000个文件上运行上述命令。我怀疑那会杀死我的电脑石头! :) – 2008-11-11 19:48:36

+0

它会淹死其他进程,但Linux调度程序非常擅长确保进程不会完全饿死。这里的问题是内存使用情况,因为分页确实会影响性能。 – sep332 2008-11-11 19:50:25

6

This perl program适合您的需求相当好,你只是这样做:

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

的答案一般问题是困难的,因为这取决于你正在并行的事情的细节。 另一方面,为了这个特定的目的,你应该使用pbzip2而不是普通的bzip2(很可能已经安装了pbzip2,或者至少在版本库或发行版中)。看到这里的细节:http://compression.ca/pbzip2/

2

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

你有没有都一样HD驱动器上执行一个简单的两个大文件副本在同一时间?我通常会更快地复制一个,然后再复制一个。

我知道这个任务涉及到一些CPU功率(bzip2的要求很高的压缩方法),但尝试才去的“挑战”的路径,我们所有的技术人员往往更经常比需要选择测量第一CPU的负载。

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以上。你可能想要做的很好,以防万一别人想在你使用机器时使用机器。

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 
14

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

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