2008-11-11 5 views
6

Я часто пишу просто для петли, чтобы выполнить операцию много файлов, например:Easy параллелизм

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

Это кажется немного удручает, что на моей 4-ядерной машине только одно ядра привыкает. . Есть ли простой способ добавить параллелизм в мой сценарий оболочки?

EDIT: Чтобы представить немного больше контекста для моих проблем, жаль, что я не был более ясен, чтобы начать с!

Я часто хочу запускать простые (иш) сценарии, такие как график графика, сжимать или распаковывать или запускать некоторую программу на наборах данных разумного размера (обычно от 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 $" `- это именно то, что нужно для поиска! (Кроме того, ваше регулярное выражение будет соответствовать именам файлов, например foozxmlzbz, но это другая и несущественная проблема). – 2008-11-11 20:42:58

+0

Ждите Эвана, у xargs есть аргумент, обозначенный «-P» для меня, для количества процессов! So: найти. | grep ".xml.bz2 $" | xargs -n1 -P3 bzip2 делает то, что я хочу Как долго имеет xargs, что для ?? – 2008-11-11 21:50:59

ответ

1

Если вы должны были решить эту проблему сегодня вы бы, вероятно, использовать такой инструмент, как GNU Parallel (если не является специализированным распараллеливание инструментом ваша задача, как pbzip2):

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

Чтобы узнать больше:

1

Я думаю, вы могли бы к следующему

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

Но что бы закрутить однако многие процессы, как у вас есть файлы мгновенно и не является оптимальным, так как просто работает четыре процесса одновременно.

+0

Это было бы нормально для небольших заданий, но я выполнял приведенную выше команду примерно на 5000 файлов. Я подозреваю, что убил бы мой компьютерный камень мертвым! :) – 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

Я нахожу этот вид работы контрпродуктивным. Причина в том, что чем больше процессов обращаются к диску в то же время, тем выше время чтения/записи, поэтому конечный результат заканчивается в течение более длительного времени. Узкое место здесь не будет проблемой ЦП, независимо от того, сколько ядер у вас есть.

Неужели вы когда-либо выполняли простые две большие копии файлов одновременно на одном HD-диске? Обычно я быстрее копирую один, а затем другой.

Я знаю, что эта задача связана с некоторой мощностью процессора (bzip2 требует сложного метода сжатия), но попробуйте измерить загрузку первого процессора перед тем, как перейти к «сложному» пути, который мы все технические специалисты предпочитаем выбирать гораздо чаще, чем необходимо.

4

gnu make имеет приятный параллелизм (например, -j 5), который будет работать в вашем случае. Создание Makefile

%.xml.bz2 : %.xml 


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

затем сделать

nice make -j 5 

заменить '5' с некоторым числом, вероятно, 1 больше, чем число процессоров. Возможно, вы захотите сделать «приятным» это на случай, если кто-то хочет использовать машину, пока вы на ней.

2

Я сделал что-то подобное для 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