J'essaie de faire un nombre record sur un fichier gzip de 7,6 Go. J'ai trouvé peu d'approches en utilisant la zcat
commande.
$ zcat T.csv.gz | wc -l
423668947
Cela fonctionne mais cela prend trop de temps (plus de 10 minutes pour obtenir le décompte). J'ai essayé quelques autres approches comme
$ sed -n '$=' T.csv.gz
28173811
$ perl -lne 'END { print $. }' < T.csv.gz
28173811
$ awk 'END {print NR}' T.csv.gz
28173811
Ces trois commandes s'exécutent assez rapidement mais donnent un nombre incorrect de 28173811.
Comment effectuer un décompte d'enregistrements en un minimum de temps?
Réponses:
Les
sed
,perl
et lesawk
commandes que vous mentionnez peuvent être correctes, mais ils lu tous les comprimés de données et compte des sauts de ligne dans ce. Ces caractères de nouvelle ligne n'ont rien à voir avec les caractères de nouvelle ligne des données non compressées.Pour compter le nombre de lignes dans les données non compressées, il est impossible de les décompresser. Votre approche avec
zcat
est la bonne approche et comme les données sont si volumineuses, il faudra du temps pour les décompresser.La plupart des utilitaires traitant de la
gzip
compression et de la décompression utiliseront très probablement les mêmes routines de bibliothèque partagée pour ce faire. La seule façon de l'accélérer serait de trouver une implémentation deszlib
routines plus rapides que celles par défaut, et de reconstruire par exemplezcat
pour les utiliser.la source
zcat
. Une partie importante du travail dezcat
génère la sortie réelle. Mais si vous ne comptez que des\n
caractères, ce n'est pas nécessaire.gzip
la compression fonctionne essentiellement en remplaçant les chaînes longues courantes par des chaînes plus courtes. Il vous suffit donc de vous préoccuper des longues chaînes du dictionnaire qui contiennent un\n
et de compter leur occurrence (pondérée). Par exemple, en raison des règles anglaises,.\n
est une chaîne commune de 16 bits.Utilisez unpigz.
La réponse de Kusalananda est correcte, vous aurez besoin de décompresser le fichier entier pour analyser son contenu.
/bin/gunzip
le fait aussi vite que possible, sur un seul cœur. Pigz est une implémentation parallèlegzip
qui peut utiliser plusieurs cœurs.Malheureusement, la décompression de fichiers lui - même gzip normal ne peut pas être parallélisés, mais
pigz
ne offre une version amélioréegunzip
,unpigz
qui fait des travaux connexes tels que la lecture, l' écriture et la somme de contrôle dans un thread séparé. Dans certains tests rapides,unpigz
est presque deux fois plus rapide quegunzip
sur ma machine Core i5.Installez
pigz
avec votre gestionnaire de paquets préféré et utilisezunpigz
au lieu degunzip
ouunpigz -c
au lieu dezcat
. Votre commande devient donc:Tout cela suppose que le goulot d'étranglement est le CPU, pas le disque, bien sûr.
la source
pigz
page de manuel indique que la décompression ne peut pas être parallélisée, du moins pas sans des flux de dégonflage spécialement préparés à cet effet. Par conséquent, pigz utilise un seul thread (le thread principal) pour la décompression, mais créera trois autres threads pour la lecture, l'écriture et le calcul de vérification, ce qui peut accélérer la décompression dans certaines circonstances . Pourtant, comme vous, je trouve que c'est au moins deux fois plus rapide quegzip
, sinon à cause du parallélismeLe problème avec tous les pipelines, c'est que vous doublez essentiellement le travail. Quelle que soit la rapidité de la décompression, les données doivent toujours être transférées vers un autre processus.
Perl a PerlIO :: gzip qui vous permet de lire directement les flux gzippés. Par conséquent, il pourrait offrir un avantage même si sa vitesse de décompression peut ne pas correspondre à celle de
unpigz
:Je l'ai essayé avec un fichier compressé gzip de 13 Mo (décompresse à 1,4 Go) sur un ancien MacBook Pro 2010 avec 16 Go de RAM et un vieux ThinkPad T400 avec 8 Go de RAM avec le fichier déjà dans le cache. Sur Mac, le script Perl était significativement plus rapide que l'utilisation de pipelines (5 secondes contre 22 secondes), mais sur ArchLinux, il a perdu à unpigz:
contre
et
De toute évidence, l'utilisation
unpigz -c file.gz | wc -l
est la gagnante ici en termes de vitesse. Et, cette simple ligne de commande bat sûrement l'écriture d'un programme, aussi court soit-il.la source
gzip | wc
a la même vitesse que votre script perl. Etpigz | wc
c'est deux fois plus rapide.gzip
fonctionne à la même vitesse, peu importe si j'écris la sortie dans / dev / null ou pipe danswc
Ce que je crois, c'est que la "bibliothèque gzip" utilisée par perl est plus rapide que l'outil de ligne de commande gzip. Il y a peut-être un autre problème spécifique Mac / Darwin avec les tuyaux. Il est toujours étonnant que cette version de perl soit compétitive.zcat
et pire queunpigz
. Je suis étonné de voir à quel point le pipeline est plus rapide sur le système Linux que sur le Mac. Je ne m'attendais pas à cela, même si j'aurais dû, comme je l'ai déjà observé, que le même programme s'exécutait plus rapidement sur une machine virtuelle Linux à processeur limité sur ce même Mac que sur du métal nu.zcat | wc -l
et 5,5 secondes pour votre script perl. Honnêtement, je suis étonné de la variation que les gens rapportent ici, en particulier entre Linux et MacOS X!wc -l
prend 2,5 secondes.gzcat compressed.gz > /dev/null
prend 2,7 secondes. Pourtant, le pipeline prend 22 secondes. Si j'essaie GNUwc
, cela ne prend qu'une demi-seconde sur le fichier décompressé, mais 22 secondes dans le pipeline. GNUzcat
prend deux fois plus de temps à s'exécuterzcat compressed.gz > /dev/null
. C'est sur Mavericks, ancien processeur Core 2 Duo, 16 Go de RAM, SSD Crucial MX100.La réponse de Kusalananda est généralement correcte. Pour compter les lignes, vous devez rechercher des sauts de ligne. Cependant, il est théoriquement possible de rechercher des sauts de ligne sans décompresser complètement le fichier.
gzip utilise la compression DEFLATE. DEFLATE est une combinaison de l'encodage LZ77 et Huffman. Il peut y avoir un moyen de comprendre uniquement le nœud de symbole Huffman pour la nouvelle ligne et d'ignorer le reste. Il existe presque certainement un moyen de rechercher des sauts de ligne codés à l'aide de L277, de conserver un nombre d'octets et d'ignorer tout le reste.
Donc, à mon humble avis, il est théoriquement possible de trouver une solution plus efficace que unpigz ou zgrep. Cela étant dit, ce n'est certainement pas pratique (à moins que quelqu'un ne l'ait déjà fait).
la source
Peut être fait en utilisant
zgrep
un-c
indicateur et un$
paramètre.Dans ce cas, -c indique à la commande de sortir le nombre de lignes correspondantes et l'expression régulière $ correspond à la fin de la ligne pour correspondre à chaque ligne ou au fichier.
Comme l'a commenté @ StéphaneChazelas -
zgrep
est seulement autour d' un scriptzcat
etgrep
il devrait fournir des performances similaires à la suggestion originale dezcat | wc -l
la source
zgrep
est généralement un script qui invoquezcat
(commegzip -dcq
) pour décompresser les données et les alimentergrep
, donc ça ne va pas aider.Comme vous pouvez le voir, la plupart des réponses essaient d'optimiser ce qu'il peut: le nombre de commutateurs de contexte et d'E / S inter-processus. La raison en est que c'est le seul que vous pouvez facilement optimiser ici.
Maintenant, le problème est que son besoin en ressources est presque négligeable par rapport au besoin en ressources de la décompression. C'est pourquoi les optimisations ne feront vraiment rien de plus rapide.
Là où il pourrait être vraiment accéléré, ce serait un algorithme non-gzip modifié (c'est-à-dire la décompression), qui exclut la production réelle du flux de données décompressé; il calcule plutôt le nombre de sauts de ligne dans le flux décompressé à partir du flux compressé . Ce serait difficile, cela nécessiterait une connaissance approfondie de l'algorithme de gzip (une combinaison des algorithmes de compression LZW et Huffman ). Il est fort probable que l'algorithme ne permet pas d'optimiser significativement le temps de décompression avec l'éclair, qu'il suffit de connaître les décomptes de la nouvelle ligne. Même si cela était possible, une nouvelle bibliothèque de décompression gzip aurait dû être développée (elle n'existe pas jusqu'à ce que nous le sachions).
La réponse réaliste à votre question est que non, vous ne pouvez pas le faire beaucoup plus rapidement.
Vous pouvez peut-être utiliser une décompression gzip parallélisée, si elle existe. Il pourrait utiliser plusieurs cœurs de processeur pour la décompression. S'il n'existe pas, il pourrait être développé assez facilement.
Pour le xz , il existe un compresseur parallèle (pxz).
la source