9
votes

Comment rendre ce script SED plus rapidement?

J'ai hérité de cet extrait de script SED qui tente de supprimer certains espaces vides: xxx

qui fonctionne sur un fichier d'environ 1 Go de grande taille. Ce script fonctionne pendant 2 heures sur notre serveur UNIX. Des idées comment accélérer?

Notes que le \ S signifie qu'un espace et \ t représente un onglet, le script actuel utilise l'espace et l'onglet réels et non de ces symboles

Le fichier d'entrée est un fichier délimité de tuyau et se trouve localement non sur le réseau. Les 4 lignes sont dans un fichier exécuté avec sed -f


5 commentaires

Comment appelez-vous SED? Est-ce que le fichier est définitivement sur votre disque local et non, disons, sur un montage NFS?


Fichier sur le disque local. J'invoque SED avec sed -f


Veuillez donner la ligne de commande complète que vous utilisez. LIME SED -F lit de stdin et écrit à stdout, ce qui n'est évidemment pas ce que vous faites.


Je ne pense pas que ce soit vraiment nécessaire ... supposez simplement SED -F sortie.txt


Je viens d'essayer mon implémentation C sur un fichier de données 1.2GIB rempli d'exemple de données. Il a fallu tous les 4m17 sur un Pentium III de 10 ans de 800 MHz. Bien que cela puisse citer, il peut varier en fonction de la contribution réelle, je pense qu'il y a de bonnes chances que cela dépend de manière significative de votre script SED;)


11 Réponses :


2
votes

Il me semble que vous me semble à partir de votre exemple, vous nettoyez l'espace blanc depuis le début et la fin des champs délimités (|) dans un fichier texte. Si je devais faire cela, je changerais l'algorithme en ce qui suit:

for each line
    split the line into an array of fields
    remove the leading and trailing white space
    join the fields back back together as a pipe delimited line handling the empty first field correctly.


2 commentaires

Pouvez-vous suggérer une commande awk pour faire cela? Désolé pas un expert awk


J'ai testé cet algorithme en utilisant AWK (dans le même sens que les programmes AWK proposés par D. Williamson et LevisleVvis85), et il était un peu plus lent que le script SED de l'OP et un peu plus lent que les versions optimisées du script SED. Donc, je ne suis pas convaincu que cette approche générale (de diviser les enregistrements dans des champs avant la substitution de la structure) devrait entraîner une vitesse de vitesse (quelle que soit la langue).



2
votes

Essayez de changer les deux premières lignes à: xxx


2 commentaires

Mes tests n'ont trouvé aucune différence entre cela et les faire séparément.


Mon test a trouvé cela pour diminuer le temps nécessaire pour analyser un fichier de 250 Mo. J'ai également trouvé une nouvelle diminution en éliminant les options g où ce n'est pas nécessaire.



0
votes

Essayez de le faire dans une commande:

sed 's/[^|]*(|.*|).*/\1/'


1 commentaires

Pouvez-vous fournir des données de test? Il est difficile d'écrire correctement une regexp sans tests :)



0
votes

Avez-vous essayé Perl? Cela peut être plus rapide.

#!/usr/local/bin/perl -p

s#[\t ]+\|#|#g;
s#\|[\t ]+#|#g;
s#[\t ]*$##;
s#^\|#null|#;


0 commentaires

1
votes

Ce script Perl devrait être beaucoup plus rapide xxx

essentiellement, assurez-vous que vos regex sont compilés une fois (le drapeau "O ') et non besoin d'utiliser" g "sur les regexes qui s'appliquent uniquement à la fin et au début de la ligne.

aussi, [\ s \ t] * est équivalent à \ s *


1 commentaires

Le drapeau "O" est redondant dans ce contexte. Perl compile toujours une nouvelle fois une refonte une fois que cela a une variable à l'intérieur.



1
votes

Cela pourrait fonctionner. J'ai seulement testé un peu. XXX


1 commentaires

Les tests préliminaires montrent cela pour exécuter à peu près à la même vitesse que les versions sed .



1
votes

Que diriez-vous de Perl: xxx

EDIT: Approche modifiée de manière significative. Sur ma machine, cela est presque 3 fois plus rapide que votre script SED.

Si vous avez vraiment besoin de la meilleure vitesse possible, écrivez un programme C spécialisé pour effectuer cette tâche.


1 commentaires

Sur ma machine, il est un peu plus lent que le script SED de l'OP et prend deux fois aussi longtemps qu'une version plus optimisée du script SED de OP.



1
votes

Utilisez GAWK, pas SED.

awk -vFS='|' '{for(i=1;i<=NF;i++) gsub(/ +|\t+/,"",$i)}1' OFS="|"  file


0 commentaires

3
votes

Mes tests ont indiqué que sed code> peut devenir un processeur lié assez facilement sur quelque chose comme ça. Si vous avez une machine multi-noyau, vous pouvez essayer de frai plusieurs processus code> SED CODE> avec un script qui ressemble à ceci:

#!/bin/sh
INFILE=data.txt
OUTFILE=fixed.txt
SEDSCRIPT=script.sed
SPLITLIMIT=`wc -l $INFILE | awk '{print $1 / 20}'`

split -d -l $SPLITLIMT $INFILE x_

for chunk in ls x_??
do
  sed -f $SEDSCRIPT $chunk > $chunk.out &
done

wait 

cat x_??.out >> output.txt

rm -f x_??
rm -f x_??.out


2 commentaires

Utilisation inutile de ls . Faites cela à la place: pour le morceau en x _ ?? et le globbing est trié et sans avoir besoin d'une boucle ici: cat x _ ??. Out> sortie.txt


Édité pour inclure les commentaires de Dennis.



30
votes

Le meilleur que j'ai pu faire avec SED, était ce script: xxx

dans mes tests, cela a couru environ 30% plus rapidement que votre script SED. L'augmentation de la performance provient de la combinaison des deux premières fends et d'omettre le drapeau "G" où ce n'est pas nécessaire.

Cependant, 30% plus rapide n'est qu'une amélioration légère (il devrait toujours prendre environ une heure et un la moitié pour exécuter le script ci-dessus sur votre fichier de données de 1 Go). Je voulais voir si je pouvais mieux faire mieux.

À la fin, aucune autre méthode que j'ai essayée (AWK, Perl et d'autres approches avec SED) a encore augmenté, sauf - bien sûr - la mise en œuvre ordinaire OL 'C. Comme on pouvait s'y attendre avec c, le code est un peu verbeux pour l'affichage ici, mais si vous voulez un programme susceptible d'être plus rapide que toute autre méthode, vous voudrez peut-être Regardez-y .

dans mes tests, la mise en œuvre C se termine dans environ 20% du temps nécessaire pour votre SED scénario. Donc, cela peut prendre environ 25 minutes environ pour exécuter votre serveur UNIX.

Je n'ai pas passé beaucoup de temps à optimiser la mise en œuvre de C. Il ne fait aucun doute qu'il y a plusieurs endroits où l'algorithme pourrait être amélioré, mais franchement, je ne sais pas s'il est possible de raser une durée importante au-delà de ce qu'elle atteint déjà. Si quelque chose, je pense que cela place certainement une limite supérieure sur quel type de performance à laquelle vous pouvez vous attendre d'autres méthodes (SED, AWK, Perl, Python, etc.).

EDIT: La version originale avait un bogue mineur qui lui faisait éventuellement imprimer la mauvaise chose à la fin de la sortie (par exemple, pourrait imprimer une "null" qui ne devrait pas être là). J'ai eu un peu de temps aujourd'hui pour y regarder et résoudre ce problème. J'ai également optimisé un appel à Strlen () qui lui a donné une autre légère performance Boost.


1 commentaires

+1 Pour une quantité impressionnante de travail pour mettre en œuvre une solution plus rapide et le tester correctement plutôt que de simplement en supposer que ce sera plus rapide.



0
votes

Je pense que le * code> dans les expressions régulières de la question et la plupart des réponses peuvent être un ralentissement majeur par rapport à l'utilisation d'un + code>. Considérons le premier remplacement de la question xxx pré>

code> correspond à zéro ou plusieurs éléments suivis par un | code>, d'où chaque | code> est remplacé même ceux qui n'ont pas besoin de remplacer. Changer le remplacement en être p> xxx pré>

ne changera que les caractères | code> précédé d'un ou plusieurs espaces et onglets. P>

Je n'ai pas SED disponible, mais j'ai fait une expérience avec Perl. Sur les données, j'ai utilisé le script avec le * code> a pris presque 7 fois plus longtemps que le script avec + code>. P>

Les temps étaient cohérents à travers les courses. Pour le + code> La différence entre les temps minimum et maximum était de 4% de la moyenne et du * code> il était de 3,6%. Le rapport entre la moyenne était de 1 :: 6.9 pour + code> :: * code>. P>

Détails de l'expérience forte> p>

testé à l'aide d'un fichier de 80 Mo avec un peu plus de 180000 occurrences de [st] \. code>, ce sont les caractères minuscules S code> et t code >. p>

Le test a utilisé un fichier de commande de lot avec 30 de chacune de ces deux commandes, une étoile alternée et plus. p>

c:\test> perl -v
This is perl 5, version 16, subversion 3 (v5.16.3) built for MSWin32-x64-multi-thread
(with 1 registered patch, see perl -V for more detail)

Copyright 1987-2012, Larry Wall

Binary build 1603 [296746] provided by ActiveState http://www.ActiveState.com
Built Mar 13 2013 13:31:10


0 commentaires