Ich versuche, eine Rekordzählung für eine 7,6-GB-gzip-Datei durchzuführen. Ich habe mit dem zcat
Befehl nur wenige Ansätze gefunden .
$ zcat T.csv.gz | wc -l
423668947
Dies funktioniert, aber es dauert zu lange (mehr als 10 Minuten, um die Zählung durchzuführen). Ich habe noch ein paar Ansätze ausprobiert wie
$ sed -n '$=' T.csv.gz
28173811
$ perl -lne 'END { print $. }' < T.csv.gz
28173811
$ awk 'END {print NR}' T.csv.gz
28173811
Alle drei Befehle werden ziemlich schnell ausgeführt, geben jedoch eine falsche Anzahl von 28173811 an.
Wie kann ich in kürzester Zeit eine Datensatzzählung durchführen?
Antworten:
Die
sed
,perl
undawk
Befehle, die Sie erwähnen, mögen korrekt sein, aber alle lesen die komprimierten Daten und zählen darin die Zeilenumbrüche. Diese Zeilenumbruchzeichen haben nichts mit den Zeilenumbruchzeichen in den unkomprimierten Daten zu tun.Um die Anzahl der Zeilen in den unkomprimierten Daten zu zählen, führt kein Weg daran vorbei, sie zu dekomprimieren. Ihr Ansatz mit
zcat
ist der richtige Ansatz , und da die Daten so groß ist, es wird einige Zeit dauern , um es zu dekomprimieren.Die meisten Dienstprogramme, die sich mit
gzip
Komprimierung und Dekomprimierung befassen, verwenden dazu wahrscheinlich dieselben Routinen für gemeinsam genutzte Bibliotheken. Die einzige Möglichkeit, dies zu beschleunigen, besteht darin, eine Implementierung derzlib
Routinen zu finden, die irgendwie schneller als die Standardroutinen sind, und diese beispielsweise neuzcat
zu erstellen, um sie zu verwenden.quelle
zcat
. Ein wesentlicher Teil der Arbeit vonzcat
ist die Erzeugung der tatsächlichen Leistung. Wenn Sie jedoch nur\n
Zeichen zählen, ist dies nicht erforderlich.gzip
Die Komprimierung funktioniert im Wesentlichen, indem herkömmliche lange Zeichenfolgen durch kürzere Zeichenfolgen ersetzt werden. Sie müssen sich also nur um die langen Zeichenfolgen im Wörterbuch kümmern, die ein enthalten\n
, und das (gewichtete) Vorkommen dieser zählen. ZB ist aufgrund englischer Regeln.\n
eine übliche 16-Bit-Zeichenfolge.Verwenden Sie Unpigz.
Kusalananda Antwort ist richtig, Sie werden zu dekomprimieren müssen , dass gesamte Datei seinen Inhalt zu scannen.
/bin/gunzip
erledigt dies so schnell wie möglich auf einem einzigen Kern. Pigz ist eine parallele Implementierunggzip
, die mehrere Kerne verwenden kann.Leider kann die Dekomprimierung normaler gzip-Dateien nicht parallelisiert werden,
pigz
bietet jedoch eine verbesserte Version vongunzip
,unpigz
die verwandte Arbeiten wie Lesen, Schreiben und Prüfsummen in einem separaten Thread ausführt. In einigen schnellen Benchmarksunpigz
ist es fast doppelt so schnell wiegunzip
auf meinem Core-i5-Rechner.Installieren Sie
pigz
mit Ihrem bevorzugten Paket-Manager und verwenden Sieunpigz
anstelle vongunzip
oderunpigz -c
anstelle vonzcat
. So wird Ihr Befehl:Das alles setzt voraus, dass der Engpass die CPU ist und nicht die Festplatte.
quelle
pigz
Manpage steht, dass die Dekomprimierung nicht parallelisiert werden kann, zumindest nicht ohne speziell dafür vorbereitete Deflate-Streams. Folglich verwendet pigz einen einzelnen Thread (den Haupt-Thread) für die Dekomprimierung, erstellt jedoch drei weitere Threads zum Lesen, Schreiben und Überprüfen der Berechnung, wodurch die Dekomprimierung unter bestimmten Umständen beschleunigt werden kann . Dennoch, wie Sie finde ich, ist es mindestens doppelt so schnell wiegzip
, wenn nicht wegen der ParallelitätDas Problem bei allen Pipelines ist, dass Sie die Arbeit im Wesentlichen verdoppeln. Egal wie schnell die Dekomprimierung ist, die Daten müssen immer noch zu einem anderen Prozess verschoben werden.
Perl hat PerlIO :: gzip , mit dem Sie gzippte Streams direkt lesen können. Daher könnte es einen Vorteil bieten, selbst wenn seine Dekomprimierungsgeschwindigkeit nicht mit der folgenden übereinstimmt
unpigz
:Ich habe es mit einer komprimierten 13-MB-GZIP-Datei (dekomprimiert auf 1,4 GB) auf einem alten 2010 MacBook Pro mit 16 GB RAM und einem alten ThinkPad T400 mit 8 GB RAM versucht, wobei sich die Datei bereits im Cache befindet. Auf dem Mac war das Perl-Skript deutlich schneller als die Verwendung von Pipelines (5 Sekunden gegenüber 22 Sekunden).
gegen
und
Die Verwendung von
unpigz -c file.gz | wc -l
ist hier eindeutig der Gewinner, sowohl in Bezug auf die Geschwindigkeit. Und diese einfache Befehlszeile ist mit Sicherheit besser als ein Programm zu schreiben, wie kurz es auch sein mag.quelle
gzip | wc
hat das die selbe Geschwindigkeit wie dein Perl Skript. Undpigz | wc
ist doppelt so schnell.gzip
Läuft mit der gleichen Geschwindigkeit, unabhängig davon, ob ich die Ausgabe in / dev / null oder pipe in schreibe.wc
Ich glaube, dass die von Perl verwendete "gzip-Bibliothek" schneller ist als das gzip-Befehlszeilentool. Vielleicht gibt es ein anderes Mac / Darwin-spezifisches Problem mit Pipes. Es ist immer noch erstaunlich, dass diese Perl-Version überhaupt wettbewerbsfähig ist.zcat
und schlechter als zu seinunpigz
. Ich bin erstaunt, wie viel schneller die Pipeline auf dem Linux-System ist als auf dem Mac. Ich hatte nicht damit gerechnet, obwohl ich, wie ich einst beobachtete, dasselbe Programm auf einer Linux-VM mit begrenzter CPU auf demselben Mac schneller laufen sollte als auf Bare Metal.zcat | wc -l
und 5,5 Sekunden für Ihr Perl-Skript. Ehrlich gesagt bin ich erstaunt über die Variationen, über die hier berichtet wird, insbesondere zwischen Linux und MacOS X!wc -l
dauert dies 2,5 Sekunden.gzcat compressed.gz > /dev/null
dauert 2,7 Sekunden. Die Pipeline dauert jedoch 22 Sekunden. Wenn ich GNU versuchewc
, dauert es nur eine halbe Sekunde für die dekomprimierte Datei, aber 22 Sekunden in der Pipeline. Diezcat
Ausführung von GNU dauert doppelt so langezcat compressed.gz > /dev/null
. Dies ist auf Mavericks, alten Core 2 Duo-CPU, 16 GB RAM, Crucial MX100 SSD.Kusalanandas Antwort ist größtenteils richtig. Um Zeilen zu zählen, müssen Sie nach neuen Zeilen suchen. Theoretisch ist es jedoch möglich, nach Zeilenumbrüchen zu suchen, ohne die Datei vollständig zu dekomprimieren.
gzip verwendet die DEFLATE-Komprimierung. DEFLATE ist eine Kombination aus LZ77- und Huffman-Codierung. Es kann eine Möglichkeit geben, nur den Huffman-Symbolknoten für Zeilenumbruch herauszufinden und den Rest zu ignorieren. Es gibt mit ziemlicher Sicherheit eine Möglichkeit, nach mit L277 codierten Zeilenumbrüchen zu suchen, die Anzahl der Bytes beizubehalten und alles andere zu ignorieren.
Meiner Meinung nach ist es theoretisch möglich, eine effizientere Lösung als unpigz oder zgrep zu finden. Davon abgesehen ist es sicherlich nicht praktikabel (es sei denn, jemand hat es bereits getan).
quelle
Kann mit getan werden
zgrep
mit-c
flag und$
parameter durchgeführt werden.In diesem Fall weist -c den Befehl an, die Anzahl der übereinstimmenden Zeilen auszugeben, und der reguläre Ausdruck $ stimmt mit dem Zeilenende überein, sodass er mit jeder Zeile oder Datei übereinstimmt.
Wie kommentiert von @ StéphaneChazelas -
zgrep
ist nur ein Skript umzcat
undgrep
es soll eine ähnliche Leistung auf den ursprünglichen Vorschlag liefernzcat | wc -l
quelle
zgrep
ist im Allgemeinen ein Skript, daszcat
(dasselbe wiegzip -dcq
) aufruft, um die Daten zu dekomprimieren und zu füttern. Esgrep
wird also nicht helfen.Wie Sie sehen, versuchen die meisten Antworten zu optimieren, was möglich ist: die Anzahl der Kontextwechsel und der prozessübergreifenden E / A. Dies ist der einzige Grund, warum Sie hier einfach optimieren können.
Das Problem ist nun, dass sein Ressourcenbedarf gegenüber dem Ressourcenbedarf der Dekomprimierung nahezu vernachlässigbar ist. Aus diesem Grund werden die Optimierungen nichts wirklich schneller machen.
Wo es wirklich beschleunigt werden könnte, wäre es ein modifizierter Un-Gzip-Algorithmus (dh Dekomprimierungsalgorithmus), der die tatsächliche Erzeugung des dekomprimierten Datenstroms ausschließt. Stattdessen wird nur die Anzahl der Zeilenumbrüche im dekomprimierten Stream aus dem komprimierten berechnet . Es wäre schwierig, es würde tiefe Kenntnisse des gzip-Algorithmus erfordern (eine Kombination der LZW- und Huffman- Komprimierungsalgorithmen). Es ist sehr wahrscheinlich, dass der Algorithmus es nicht möglich macht, die Dekomprimierungszeit mit dem Blitz signifikant zu optimieren. Wir müssen nur die Zeilenumbrüche kennen. Selbst wenn es möglich wäre, hätte im Wesentlichen eine neue gzip-Dekomprimierungsbibliothek entwickelt werden müssen (diese existiert erst, wenn man es weiß).
Die realistische Antwort auf Ihre Frage lautet: Nein, Sie können es nicht wesentlich schneller machen.
Möglicherweise könnten Sie eine parallelisierte gzip-Dekomprimierung verwenden, falls vorhanden. Es könnten mehrere CPU-Kerne für die Dekomprimierung verwendet werden. Wenn es nicht existiert, könnte es relativ leicht entwickelt werden.
Für das xz gibt es einen Parallelkompressor (pxz).
quelle