Hello, On Tue, 24 Jun 2003, Jan Trippler wrote:
On Mon, 23 Jun 2003 at 03:00 (+0200), David Haller wrote:
On Mon, 23 Jun 2003, Jan Trippler wrote:
# Datei lesen die "usage: $0 Dateiname\n" unless defined $ARGV[0]; open DATEI, "$ARGV[0]" or die "Fehler beim Oeffnen der Datei ($!)\n";
Die Datei sollte man IMO explizit "readonly" oeffnen...
my @zeilen = <DATEI>; close DATEI;
*AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA*
Das ist der gleiche Fehler wie von grepmail. Versuch das mal mit ner Datei von ein paar 100 MB!!! Stehen lassen kann man das "open".
Ich habe hier einfach die Vorlage übernommen - ich benutze dieses Konstrukt auch oft, wenn ich weiss, dass die Dateien überschaubar sind.
Ja. [..]
jan@k500:~/tmp> time ./out.pl >kunden.html real 7m32.256s Deine Variante: jan@k500:~/tmp> time ./out.pl >kunden2.html real 7m25.972s
Hm, diese Differenz ist für mich vernachlässigbar.
Hast du auch mal den Speicherverbrauch dabei angeschaut? Siehe dazu meine tests nebenan ;)
foreach (@zeilen) { # Zeilen abklappern, Zeile wird in $_ abgelegt
*ARGH* Hier wird's dann wirklich doof, wenn man sowieso zeilenweise liest, kann man gleich die Datei hernehmen.
while(<DATEI>) { # Zeilen abklappern, Zeile wird in $_ abgelegt
(ja, der Kommentar stimmt so!)
Es wird nur dann doof, wenn Du sie nicht in ein Array gelesen hast. Wenn Du unbedingt zeilenweise lesen willst, kannst Du natürlich nicht über ein Array iterieren.
Klar, ich haette da vielleicht '...' verwenden sollen. Das bezog sich auch noch darauf, dass ueberhaupt in ein Array gelesen wird. Liest man in ein Array, dann ist das foreach natuerlich richtig ;)
chomp; # \n wegwerfen next if /^ *$/; # leere Zeilen wegschmeissen
Wuerde ich andersrum schreiben, bei leeren Zeilen faellt dann der ueberfluessige Aufruf von 'chomp' weg:
next if /^\s*$/; # leere Zeilen wegschmeissen chomp; # \n wegwerfen
Jau, spart einen Funktionsaufruf.
Ich versuch immer so zu programmieren...
undef ($daten{$out}); # Hash-Key wegschmeissen
Ich wuerde eher jew. beim Auftauchen von 'Kdnr' das gesamte hash reinitialisieren: [..] print "</tr>\n"; # Ende Tabellenzeile %daten = (); # hash reinitialisieren }
## in $_ steht immer noch das neue Kdnr: ...
Was ist der Unterschied? Ich initialisiere zwar nicht das ganze Array, weil ich nur alle (in der Tabelle benutzten) Keys plattmache. Der Effekt ist aber der gleiche.
Jup.
Ich weiss nicht, wie Perl das intern handhabt und was performanter ist.
Nachtrag: Die oberen beiden Tests liefen mit Deiner Variante der Initialisierung. [..] IMHO zeigt das, dass die Initialisierung einzelner Keys deutlich fixer ist, als die des gesamten Hash (immerhin ca. 15%).
Jo, scheint so. $ time perl -e 'for ( 0 .. 500000 ) { $foo{$_} = $_; } undef %foo;' real 0m6.133s $ time perl -e 'for ( 0 .. 500000 ) { $foo{$_} = $_; } %foo = ();' real 0m6.080s $ time perl -e 'for ( 0 .. 500000 ) { $foo{$_} = $_; undef($foo{$_}); }' real 0m5.487s Die 'sys' Werte sind jew. irrelevant aehnlich. Hm. Die ltrace (-S) Ausgaben sehen in beiden Varianten aehnlich aus... Ich dachte grad, dass perl bei der letzteren Variante speicher recylced, aber das scheint auch sonst der Fall zu sein: $ ltrace -S perl -e 'for ( 0 .. 50 ) { $foo{$_} = $_; undef($foo{$_}); }' 2>&1 | grep 'SYS_brk' | wc -l 23 $ ltrace -S perl -e 'for ( 0 .. 50 ) { $foo{$_} = $_; } undef(%foo);' 2>&1 | grep 'SYS_brk' | wc -l 23 'Alloc' taucht jew. nur einmal als perl_alloc auf... Also leider nichts erhellendes, warum das eine oder andere schneller ist... Da muesste man wohl mal in die perl-Sourcen schauen... Ich habe eben vermutet, dass die "vielen einzelnen" undefs langsamer waeren als ein einzelnes "wegwerfen"/reinitialisieren des hashes...
my ($key, $value) = split /:/; # neue Zeile aufspalten
Die Deklaration wuerde ich aus der Schleife rausnehmen, das ist nicht noetig. Also das 'my ($key, $value)' vor das while und dann hier nur noch:
($key, $value) = split /:/; # neue Zeile aufspalten
Warum?
Bin wieder in die Falle getappt... $ time perl -e 'for ( 0 .. 500000 ) { my %foo; $foo{$_} = $_; undef($foo{$_}); }' real 0m4.678s $ time perl -e 'my %foo; for ( 0 .. 500000 ) { $foo{$_} = $_; undef($foo{$_}); }' real 0m6.323s Das soll mir mal einer erklaeren ;) Ich glaub, ich sollte echt mal ein wenig im perl-quellcode kruschteln ;)
Mit einer lokalen Deklaration bin ich sicher, dass die Variablen nirgends sonst irrtümlich benutzt werden, da weist mich perl schon drauf hin. Du führst unnötig global gültige Variablen ein, das ist IMHO ein Weg, der Fehler provoziert.
Ack. Sowas wuerde ich sonst in einem sub haben...
Global definierte Variablen verführen immer dazu, sie einfach noch mal zu benutzen (oder aus Versehen noch mal zu benutzen - perl warnt ja dann nicht mehr), und dann wird es deutlich aufwändiger, Seiteneffekte zu vermeiden.
ACK. -dnh --
Rai"Ohje Du fröhliche"mund "...gnadenlose Weihnachtszeit. -- R. Huemmer und M. Herrmann in dasr