Paralleles packen von Dateien

D

Der_Wolf

Jungspund
Sehr geehrte Dame und Herren,

ich bin neu hier im forum deshalb begrüsse ich alle recht herzlich :).

Ich habe ein Problem, ich habe auf einem Raid Server ca 4 TB Daten. Um das Datenaufkommen zu verringern möchte ich Dateien in bestimmten Ordnern packen. Wenn ich diese Aufgabe von einem einzelnen Prozess erledigen lassen würde, würde das sehr lange dauern da nur ein Prozessor genutzt werden könnte. Ich habe ein shell script geschrieben das zu packenden Daten mittels find sucht.
Nun möchte ich mind. zwei Prozessoren parallel damit beauftragen diese gefundenen Daten zu packen.

Mein Ansatz war das Ergebnis von find in eine Textdatei zu schreiben. Sie enthält Zeilenweise jede Datei die gepackt werden muss. Nun wollte ich mit "wc" die Anzahl der Zeilen ermitteln und durch die Anzahl der zu benutzenden Prozessoren (eventuell Eingabeparameter) teilen. Anschliessend sollten "Workerprozesse" gestartet werden (ich dachte an exec ... &) die jeweils als Eingabeparameter einen Zeilenbereich für die Datei erhalten, den Dateinamen mit "cut" holen und somit vollkommen parallel arbeiten können.

Leider ist mein Wissen über shell programmierung nicht fundiert genug um dies zu realisieren.
Ich wäre euch sehr dankbar wenn ihr mir einen Denkanstoss :headup: geben könntet ob dieser Weg realisierbar ist, oder ob es viel einfacher geht.

mit freundlichen grüssen
Denny S. :brav:
 
Zuletzt bearbeitet:
Hi und willkommen im board :>
Also kurz nochmal zum verständnis du willst nicht alle gefundenen dateien in ein archiv packen und comprimieren ? sondern jede datei einzeln ?
Wenn du jede datei einzeln machen willst, würde ich persönlich das nicht mit shellskript realisieren sondern ein kleine c-proggi schreiben und mit fork() arbeiten !

Aber bestimmt gibts hier auch leute, die dir ein bsp in einem shellskript geben können
 
Danke foexle für deine Antwort :).

Ja du hast natürlich recht ich möchte jede Datei einzeln einpacken.
Mit nen C Programm und fork wäre es natürlich auch realisierbar aber ich favorisiere ein shell script.

Die Frage ist eigentlich bei meinem Ansatz wie kann ich die Zeilen der Datei (die die einzelenen Dateinamen+Pfad) enthält auf die Anzahl der Prozessoren aufteilen. "wc" gibt eine Gesamtzahl der Zeilen an, allerding weiss ich nicht wie ich dem Kommando ein Ergebnis entlocke mit dem ich rechnen kann, um die Anzahl der Zeilen durch die zu verwenden Proz. teilt.

Dann die Frage wie man an die bestimmten Zeilen ran kommt wenn man den Index hat. Entweder mit "cut" irgendwie oder mit split die Datei aufteilen in x gleiche Teile und jedem Prozessor eine Teildatei bearbeiten lassen ???????

Beim starten der Workerprozesse, geht das mit exec ..... & ??? Um parall mehere zu starten und jedem entweder eine eigene Datei zukommen lassen oder einen Indexbereich?

mit freundlichen Grüssen

Denny
 
Also ein wenig kann ich dir helfen :>

Code:
cpuAnzahl=$1

`find /verzeichnis -name *.avi >> verzeichnisse.txt`
anzahl = `cat ~/verzeichnisse.txt | wc -l`
gesAnzahl= `expr $anzahl / $cpuAnzahl`

also ungetestet dann haste die Zahl :>
 
foexle, dankeschön.

Das funktioniert schonmal :).

Code:
$CPUs 
$Anzahl 
$Teilmenge

find $1 -wholename "*suchmuster" -print  >  print.txt 
CPUs=2
Anzahl=$(cat print.txt | wc -l)
echo "Gesamtdateien $Anzahl"
echo "Gesamtkerne $CPUs"
Teilmenge=$((Anzahl/CPUs))
echo "Dateien pro Kern $Teilmenge"

Nun hab ich die Zahlen die ich brauche :).

Das nächste Problem ist ob es einen Befehl gibt um auf die Indexe der spalten gezielt zuzugreifen. oder ob man die Quelldatei in soviele Teile teilt wie man Kerne hat und jedem Kern eine extra Datei zur Verfügung stellt um diese Daten abzuarbeiten.

Ich denke die Datei teilen wäre am besten nur wie teilt man diese, bzw welches kommando ermöglicht es z.B. Zeile 100-200 in eine andere Datei zu speichern ?? Ich werds mal mit sed versuchen, falls wer ne andere Idee hat bitte posten.

mfg
Denny
 
Zuletzt bearbeitet:
ja sicher kannst du die datei teilen ....
machst ne schleife die so oft durchläuft wie $cpu groß ist,
anhand der durchlaufnummer machste ne datei wie "datei$i"
dann machste eine innere schleife die so oft durchläuft wie $teilmenge
und kopierst einfach jede zeile in datei$i

das wars... dann haste so viele dateien wie cpus und hast da so viel drin wie der durchschnitt ist... aber achtung du weist das dir evtl zeilen verloregn gehen können wegen der rundung ... oder gehen die zeilen immer auf ? also wenn du zeilen/cpu rechnest ?

greetz
 
Wie wärs mit

Code:
#!/bin/bash

LZS="
"
procs="0"
cpus="0" #selbst eintragen

for i in $(cat $1)
do
        if      [ $cpus -gt $procs ]
        then
                procs=$[ $procs+1 ]
                bzip2 $i ; procs=$[ $procs-1 ] &
        else
                sleep 1s 
        fi 
done

nicht geteste, aber es sollte zu mindest so ähnlich ablaufen.

Ich glaub aber irgendwo gelesen zu haben, dass es eine implementierung von bzip gibt, die multithreading unterstützt, vllt bist du damit glücklicher.
 
Also ihr zwei,

ich danke euch vielmals für eure Tips, aber leider komme ich heute nicht mehr zum testen.
Wenn ich Zeit habe werde ich morgen Nachmittag testen und meine Ergebnisse hier posten das auch andere was davon haben :).

@foexle: mit welchem Befehl kann man denn Zeilenweise kopieren ??

@marcellus: ja das mit der mutithreaded version von bzip klingt schon interessant, aber ich habe auch noch andere scripte die ich ausführen muss und da würde ich dann das gleiche Prinzip anwenden können um die Bearbeitung zu beschleunigen :).

mfg
Denny
 
Zuletzt bearbeitet:
@marcellus: ja das mit der mutithreaded version von bzip klingt schon interessant, aber ich habe auch noch andere scripte die ich ausfüren muss und da würde ich dann das gleiche prinzip anwenden können um die Bearbeitung zu beschleunigen :).

Deswegen hab ich dir auch das script gepostet, das packt die einträge in deiner datei zeile für zeile, wobei $cpus viele pack prozesse gleichzeitig ablaufen.


Edit: hab oben mist gebaut, es sollte eigentlich so aussehen:
Code:
#!/bin/bash

LZS="
"
procs="0"
cpus="0" #selbst eintragen

for i in $(cat $1)
do
while [ $cpus -le $procs ]
        do
                sleep 1s
        done
        procs=$[ $procs+1 ]
        $(bzip2 $i ; procs=$[ $procs-1 ] )&
done
 
Zuletzt bearbeitet:
Ich danke dir marcellus,

ich werde mal versuchen nachzuvollziehen was das Script genau macht (wie gesagt ich hab leider noch nicht so viel Erfahrung mit shell scripten, aber Übung macht den Meister :) )und es anzuwenden :)

mfg
Denny
 
Ich hab das gerade noch einmal ausprobiert und muss gestehen, dass ich doch ein ziemlicher noob bin was shell programmierung angeht, das ganze haut so nicht hin, weil durch

$(bzip2 $i ; procs=$[ $procs-1 ] )&

eine neue shell aufgemacht wird, die dann nur eine kopie von procs dekrementiert.

Ich bin mir sicher es gibt eine saubere lösung wie man das mit pointern lösen kann, aber meine jetzt funktionierende version soll dir nicht erspart bleiben ^^

Code:
#!/bin/bash

LZS="
"
cpus="0"

for i in $1
do
        while [ $cpus -le $(jobs | wc -l) ]
        do
                sleep 1s 
        done
        bzip2 $i &
done

sry für das mehrfache posten von falschem zeug, ich hab selber nicht übermäßig viel ahnung und wollt dein problem als herausforderung sehen.
 
ja kollege :> ich schreib dir doch nicht dein script :> das mussu schon selber machen... willst doch auch was lernen ... oben habsch dir einen weg beschrieben wie es gehen könnte ... nun schlägst du nach wie man schleifen baut, wie man von einer datei etwas in eine andere umlenkt und dann kannste den nächsten schritt angehen :>
 
Damit eine Applikation mehrere CPUs nutzen kann, muss sie Threading verwenden.

Da kannst du alles was mit Bash zu tun schon mal vergessen, die kann das nämlich nicht.

Sprich, du wirst eine Hochsprache wie C++ oder Java verwenden müssen, die dir Threading anbietet.

Mit Bash wird das schlicht und ergreifend nicht gehen.
 
Zuletzt bearbeitet:
@supersucker willst du damit sagen, dass es nicht möglich ist mit der bash mehrere Prozesse zu starten, oder willst du sagen, dass es nicht möglich ist, dass mehrere prozesse auf mehrere Kerne aufgeteilt werden?

Und im übrigen gibts pthreads auch für c und viele andere prozedurale sprachen auch.
 
@supersucker willst du damit sagen, dass es nicht möglich ist mit der bash mehrere Prozesse zu starten, oder willst du sagen, dass es nicht möglich ist, dass mehrere prozesse auf mehrere Kerne aufgeteilt werden?

Letzteres ist mit der Bash nicht möglich.

Und im übrigen gibts pthreads auch für c und viele andere prozedurale sprachen auch.

Äh, ja?

Hast du jetzt von mir erwartet, das ich alle Sprachen aufzähle, die Threading unterstützen?
 
Komisch, dass wenn ich das probiere mit 2 c programmen, die ein while(1) runterzählen 2 prozesse laufen, die je 99% eines kerns auslasten.
 
Komisch, dass wenn ich das probiere mit 2 c programmen, die ein while(1) runterzählen 2 prozesse laufen, die je 99% eines kerns auslasten.

Jetzt lies halt mal richtig bevor du antwortest.

Wenn du zwei separate Programme startest geht das natürlich, wir sprachen hier aber von einem Prozess und nicht von zwei separaten.

Und damit ein Prozeß mehrere CPUs nutzen kannst brauchst du Threading.

Mit einer kleinen Ausnahme:

Der Intel-Compiler bspw. kann bestimmte - triviale - Aktionen auf mehrere Prozessoren verteilen. Betonung auf trivial.
 
Zuletzt bearbeitet:
das habe ich im 2. post schon geschrieben das er C verwenden soll

also ich sehe da auch keine andere lösung ... ausser er startet für jeden CPU ein extra prozess.
also hätte er dann 3xbiz2 offen

aber denke das ist ja nicht sinn der sache
 
Zuletzt bearbeitet:
Stimmt, sry hab das überlesen, ich bin davon ausgegangen, das du von mehreren Prozessen redest, weils ums packen von vielen dateien in viele archive geht.
 
Zurück
Oben