2013-05-07 6 views
8

Ich bewerte, ob verwendet werden kann, um parallel auf einem System gespeicherte Dateien zu suchen. Es kann nur eine Datei für jeden Tag des Jahres (Doy) auf dem System geben (also maximal 366 Dateien pro Jahr). Nehmen wir an, es gibt 3660 Dateien auf dem System (ungefähr 10 Jahre Daten). Das System könnte ein Multi-CPU-Multi-Core-Linux oder ein Multi-CPU-Solaris sein.Wie füge ich eine große Anzahl von Befehlen an GNU Parallel?

Ich speichere die Suchbefehle für die Dateien in einem Array (ein Befehl pro Datei). Und das ist, was ich jetzt mache (mit bash), aber dann habe ich keine Kontrolle darüber, wie viele Suchanfragen parallel zu starten (definitiv nicht wollen, alle 3660 sucht sofort beginnen):

#!/usr/bin/env bash 
declare -a cmds 
declare -i cmd_ctr=0 

while [[ <condition> ]]; do 
    if [[ -s $cur_archive_path/log.${doy_ctr} ]]; then 
     cmds[$cmd_ctr]="<cmd_to_run>" 
     let cmd_ctr++ 
    fi 
done 

declare -i arr_len=${#cmds[@]} 
for ((i=0; i<${arr_len}; i++)); 
do 
    # Get the command and run it in background 
    eval ${cmds[$i]} & 
done 
wait 

Wenn ich parallel (das wird automatisch die max. CPUs/Kerne herausfinden und starten Sie nur so viele Suchen parallel), wie kann ich das Array cmds mit parallel verwenden und den obigen Code neu schreiben? Die andere Alternative ist es, alle Befehle in eine Datei zu schreiben und dann cat cmd_file | parallel

+0

Um pedantisch zu sein, kann in meinem Universum 10 Jahre nicht 3660 Dateien ergeben, da es nicht 10 aufeinander folgende Schaltjahre geben kann. Aber seit du "about" geschrieben hast, nehme ich an, dass du das weißt und schaue nicht in mein paralleles Universum (was mich ein bisschen traurig macht) ;-) –

+0

@Adrian Du hast recht; Ich fügte 'ungefähr' hinzu, um Schaltjahre zu berücksichtigen :) –

Antwort

6

https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Using-shell-variables sagt:

parallel echo ::: "${V[@]}" 

Sie nicht das Echo wollen, so:

parallel ::: "${cmds[@]}" 

Wenn Sie nicht brauchen, $ cmds für alles andere, dann verwenden Sie 'sem' (das ist ein Alias ​​für parallele - semaphore) https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Working-as-mutex-and-counting-semaphore

while [[ <condition> ]]; do 
    if [[ -s $cur_archive_path/log.${doy_ctr} ]]; then 
    sem -j+0 <cmd_to_run> 
    fi 
done 
sem --wait 

Sie haben nicht beschrieben, was < Bedingung> sein könnte. Wenn Sie einfach nur ein etwas wie eine for-Schleife tun könnte man das ganze Skript ersetzen mit:

parallel 'if [ -s {} ] ; then cmd_to_run {}; fi' ::: $cur_archive_path/log.{1..3660} 

(basierend auf https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Composed-commands).

+0

Danke für alle Tipps. Aber ich habe das Gefühl, die Shell wird explodieren, wenn "$ {cmds [@]}" inline erweitert wird, besonders wenn das cmds-Array 1000 Elemente/Befehle enthält? Denken Sie, es ist sicherer, die Befehle aus einer Datei zu füttern? –

+0

Wenn '$ {cmds [@]}' erweitert wird, ist das Trennzeichen zwischen mehreren Befehlen (muss ich am Ende jedes Befehls ein ';' verwenden)? Wie unterscheidet sich das von 'cat cmd_file | parallel, wo ein neues Zeilenzeichen als Trennzeichen betrachtet wird? –

+0

Ich kann Befehlszeilen von 130 KB ausführen, wenn Ihr Befehl <130 Zeichen ist, sollten Sie sicher sein. Aber persönlich würde ich entweder die Befehle entweder parallel leiten (wodurch sowohl ein Shell-Limit als auch eine temporäre Datei vermieden wird) oder die Befehle parallel generieren lassen. –

Verwandte Themen