2008-11-11 53 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