2016-06-24 13 views
3

Ich versuche eine gzip-komprimierte Datei aus mehreren Threads zu lesen.C++/C Mehrere Threads zum gleichzeitigen Lesen der gz-Datei

Ich dachte, dieses deutlich Dekompression beschleunigen würde, wie meine gzread Funktionen in mehreren Threads aus verschiedenen Datei-Offset (mit gseek) beginnen, damit sie unterschiedliche Teile der Datei lesen.

Der vereinfachte Code ist wie

// in threads 
auto gf = gzopen("file.gz",xxx); 
gzseek(gf,offset); 
gzread(xx); 
gzclose(gf); 

Zu meiner Überraschung meines Multi-Thread-Version Programm macht nicht Geschwindigkeit überhaupt auf. Die 20-Thread-Version verwendet genau die gleiche Zeit wie die Single-Thread-Version. Ich bin mir ziemlich sicher, dass das vom Diskettenengpass weit entfernt ist.

Ich denke, die zlib Inflation Funktionalität muss möglicherweise die gesamte Datei für das Lesen auch nur einen kleinen Teil zu dekomprimieren, aber ich habe keine Ahnung von ihrem Handbuch bekommen.

Wer hat eine Idee, wie man in meinem Fall beschleunigt?

+0

In der Regel wird die meiste Zeit beim Datenlesen verbraucht. Nicht in Dekompression. Stellen Sie Ihre Daten auf die schnellsten verfügbaren Medien und versuchen Sie es erneut. – GMichael

+0

@GMichael Danke für den Hinweis. Ich experimentierte dafür, in dem ich dasselbe Programm für zwei komprimierte Dateien ausführte, eine mit höher komprimierter Ebene der Größe 600M, die andere mit niedrigerer Ebene, aber der Größe 2G. Die erste Datei dauerte 22 Sekunden, während die zweite Datei 10 Sekunden verwendete. Es liegt also eher an der Dekompression. – fanbin

+0

Vielleicht versuchen Sie, in jedem Thread die gleichen Dateigriffe zu verwenden und nicht separat zu öffnen. –

Antwort

1

tl; dr: zlib ist nicht für den wahlfreien Zugriff ausgelegt.It seems possible to implement, obwohl ein vollständiges Durchlesen erforderlich ist, um einen Index zu erstellen, so dass es in Ihrem Fall möglicherweise nicht hilfreich ist.

Schauen wir uns die zlib source. gzseek ist ein Wrapper um gzseek64, die enthält:

/* if within raw area while reading, just go there */ 
if (state->mode == GZ_READ && state->how == COPY && 
     state->x.pos + offset >= 0) { 

„Innerhalb von rohem Bereich“ klingt nicht ganz richtig, wenn wir eine gzip-Datei sind zu verarbeiten. Lassen Sie uns die Bedeutung von state->how in gzguts.h nachschlagen:

int how; /* 0: get header, 1: copy, 2: decompress */ 

Rechts. Am Ende der gz_open, ein Aufruf an gz_reset Sätze how auf 0 Rückkehr in gzseek64 wir mit dieser Änderung in den Zustand am Ende:

state->seek = 1; 
state->skip = offset; 

gzread, wenn sie aufgerufen wird, verarbeitet diese mit einem Aufruf an gz_skip:

if (state->seek) { 
    state->seek = 0; 
    if (gz_skip(state, state->skip) == -1) 
     return -1; 
} 

dieser Kaninchenbau nach nur ein bisschen weiter, finden wir, dass gz_skip Anrufe gz_fetch bis gz_fetch genug Input für die Such gewünschte verarbeitet hat. gz_fetch ruft bei seiner ersten Schleifeniteration gz_look auf, wodurch state->how = GZIP festgelegt wird, wodurch gz_fetch Daten von der Eingabe dekomprimiert werden. Mit anderen Worten, Ihr Verdacht ist richtig: zlib dekomprimiert die gesamte Datei bis zu diesem Punkt, wenn Sie gzseek verwenden.

+0

Ein Lehrbuch Geek/Hack Beispiel für mich. Vielen Dank – fanbin

1

zlib Implementierung haben keine Multithreading (http://www.zlib.net/zlib_faq.html#faq21 - "Ist zlib thread-safe? - Ja. ... Natürlich sollten Sie nur auf jeden gegebenen zlib oder gzip Stream aus einem einzigen Thread zu einem Zeitpunkt.") Und Entpackt "gesamte Datei" bis zur gesuchten Position.

Und ZLIB-Format hat schlechte Ausrichtung (Bit-Ausrichtung)/keine Offset-Felder (deflate format), um parallele Dekomprimierung/Suche zu ermöglichen.

Sie können weitere Implementierungen von z versuchen (deflate/aufblasen), zum Beispiel, http://zlib.net/pigz/ (oder Schalter aus dem alten Kompression aus der Ära des Single-Core zu nicht-zlib moderne parallel Formate, xz/lzma/etwas von google)

pigz, das für die parallele Implementierung von gzip steht, ist ein voll funktionsfähiger Ersatz für gzip, der beim Komprimieren von Daten mehrere Prozessoren und mehrere Kerne ausnutzt. pigz wurde von Mark Adler geschrieben und verwendet die Bibliotheken zlib und pthread. Zur Kompilierung und Verwendung von putz lesen Sie bitte die README-Datei in der Quellcodeverteilung. Sie können die pigz manual page here.

Das Handbuch Seite ist http://zlib.net/pigz/pigz.pdf lesen und nützliche Informationen.

Es verwendet Format zlib kompatibel, jedoch angenommen Kompresse Parallel:

Jeder Teil roher deflate Strom durch einen leeren Block gespeichert wird beendet ..., um die partielle Bitstroms an einer Bytegrenze zu beenden .

Dennoch DEFLATE Format für die parallele Dekomprimierung schlecht ist:

Dekomprimierung nicht parallelisiert werden kann, zumindest nicht ohne speziell vorbereitete deflate für diesen Zweck Ströme. Als Ergebnis verwendet putz einen einzigen Thread (den Hauptthread) für die Dekomprimierung, erstellt jedoch drei weitere Threads zum Lesen, Schreiben und Überprüfen der Berechnung, was unter bestimmten Umständen die Dekomprimierung beschleunigen kann.

3

Kurze Antwort: Aufgrund der seriellen Art eines Deflate-Streams muss gzseek() alle komprimierten Daten vom Start bis zum angeforderten Suchpunkt dekodieren. Sie können also mit dem, was Sie versuchen, keinen Gewinn erzielen. Tatsächlich werden die insgesamt verbrauchten Zyklen mit dem Quadrat der Länge der komprimierten Daten zunehmen! Also tu das nicht.