Pointer ans Ende der Datei setzen mit seek
opi
- perl
Hallo,
gibt es eine Möglichkeit, den Dateizeiger direkt ans Ende einer
Datei mit seek zu setzen oder muss ich die Datei zuerst komplett
durchlaufen?
Greez,
opi
Hallo,
gibt es eine Möglichkeit, den Dateizeiger direkt ans Ende einer
Datei mit seek zu setzen oder muss ich die Datei zuerst komplett
durchlaufen?
Was genau hast du denn vor? Wenn du Daten dranhängen willst, wäre es nicht effizienter und sinnvoller, die Datei mit >> zu öffnen?
Markus.
Hallo,
gibt es eine Möglichkeit, den Dateizeiger direkt ans Ende einer
Datei mit seek zu setzen oder muss ich die Datei zuerst komplett
durchlaufen?
Was genau hast du denn vor? Wenn du Daten dranhängen willst, wäre es nicht effizienter und sinnvoller, die Datei mit >> zu öffnen?
nicht in allen Fällen.
Beispielsweise könnte man erst von einer bestimmten Stelle lesen wollen, danach am Ende schreiben.
Das schließen und neu öffnen würde hier in allen Fällen länger dauern, zudem könnte man seinen <http://de.selfhtml.org/perl/funktionen/einausgabe.htm#flock@title=exklusiven Zugriff> verlieren.
Während dem neu öffnen kann auch ein anderer Prozess Änderungen an der Datei vornehmen, was zu unerwarteten Ergebnisse führen kann. Das Resultat ist eine Sicherheitslücke. Ich empfehle mal nach "Race Condition" zu suchen.
Gruß,
Benne
Tag opi.
gibt es eine Möglichkeit, den Dateizeiger direkt ans Ende einer Datei mit seek zu setzen
Ja, siehe seek (3. Parameter).
Siechfred
Hallo Siechfred,
Ja, siehe seek (3. Parameter).
Danke. Ich bin gerade erst nach Hause gekommen, hatte die Lösung
allerdings gefunden. seek(FILE,0,2) war es.
Nun, ich möchte gerne eine Datei ab einer bestimmten Zeile lesen.
Um genau zu sein, die _letzten_ n Zeilen einer Datei. Die Datei
wächst stetig um mehrere Zeilen an.
Da jede Zeile in der Datei die gleiche Stringlänge hat, benötige ich
die Größe der Datei in Bytes, um an die Richtige Stelle in der Datei
mit seek springen zu können.
Mein bisheriges Vorgehen:
sysopen FILE,$file,O_RDONLY or die $!;
flock(FILE,LOCK_SH);
my index = [];
my $i = 0;
while (<FILE>) {
$index->[$i] = tell(FILE);
$i++;
}
seek(FILE,$index->[$i-30],0); # 30 = Anzahl Zeilen
while (<FILE>) {
# Verarbeitung
}
close FILE;
Dieses Verfahren bringts nicht mehr, da die Dateien mittlerweile
eine Größe von mehreren Gigabytes haben und der Durchlauf einfach
zu lange dauert.
Mein geplantes neues Vorgehen:
my $lsize = 500; # Zeilenlänge in Bytes
sysopen FILE,$file,O_RDONLY or die $!;
flock(FILE,LOCK_SH);
seek(FILE,0,2);
my $bytes = tell(FILE);
my $pos = $bytes-$lsize*30; # 30 = Anzahl Zeilen
seek(FILE,$pos,0);
while (<FILE>) {
# Verarbeitung
}
close FILE;
Ist das so richtig? Ich habe es noch nicht probiert und muss noch
ein wenig basteln. An dieser Stelle habe ich aber noch eine andere
Frage...
Wie splitte ich am besten jede Zeile in ihre Einzelstrings?
Mit substr oder unpack?
Eine Zeile hat zum Beispiel den Aufbau:
Spalte 1 Spalte 2 Spalte 3 Spalte 4 Spalte 5
dies ist ein test nummer 1
und noch ein test nummer 2
schon wieder ein test nummer 3
Mit split selber würde es nicht gehen, da jeder Delimiter in einer
Spalte selber vorkommen könnte.
Für Hilfe wäre ich super dankbar.
Syntaxfehler mögen mir vergeben werden :-)
Greez,
opi
Ja, siehe seek (3. Parameter).
Danke. Ich bin gerade erst nach Hause gekommen, hatte die Lösung
allerdings gefunden. seek(FILE,0,2) war es.
oder seek FILE, 0, SEEK_END
da du sowieso schon Fnctl einbindest wäre das durchaus sinnvoll (da Plattform unabhängiger - wenn man's braucht)
Nun, ich möchte gerne eine Datei ab einer bestimmten Zeile lesen.
Um genau zu sein, die _letzten_ n Zeilen einer Datei. Die Datei
wächst stetig um mehrere Zeilen an.
Da gibt's ein Modul (komm grad nicht auf den Namen) das dürfte aber im Prinzip nichts anderes machen als dein geplantes vorgehen (ausserdem magst du ja keine Module, oder ;-) )
Wie splitte ich am besten jede Zeile in ihre Einzelstrings?
Mit substr oder unpack?Eine Zeile hat zum Beispiel den Aufbau:
Spalte 1 Spalte 2 Spalte 3 Spalte 4 Spalte 5
dies ist ein test nummer 1
und noch ein test nummer 2
schon wieder ein test nummer 3Mit split selber würde es nicht gehen, da jeder Delimiter in einer
Spalte selber vorkommen könnte.
bedeutet das das jede Spalte eine fixe Länge hat und keine Tabs drin sind?
Dann würde ich substr verwenden.
Struppi.
Da gibt's ein Modul (komm grad nicht auf den Namen) das dürfte aber im Prinzip nichts anderes machen als dein geplantes vorgehen (ausserdem magst du ja keine Module, oder ;-) )
gefunden: http://search.cpan.org/~uri/File-ReadBackwards-1.04/ReadBackwards.pm
Struppi.
Hallo Struppi,
ich habe lange nichts mehr von dir gelesen :-)
oder seek FILE, 0, SEEK_END
das wußte ich noch nicht! Supi!
Nun, ich möchte gerne eine Datei ab einer bestimmten Zeile lesen.
Um genau zu sein, die _letzten_ n Zeilen einer Datei. Die Datei
wächst stetig um mehrere Zeilen an.Da gibt's ein Modul (komm grad nicht auf den Namen) das dürfte aber im Prinzip nichts anderes machen als dein geplantes vorgehen (ausserdem magst du ja keine Module, oder ;-) )
Na mittlerweile wächst mein Interesse an Modulen, da mein Perl immer
besser wird und ich viele Abläufe besser verstehe :-)
Allerdings versuche ich neues Gebiet immer zuerst ohne Modul
anzupacken.
Wie splitte ich am besten jede Zeile in ihre Einzelstrings?
Mit substr oder unpack?Eine Zeile hat zum Beispiel den Aufbau:
Spalte 1 Spalte 2 Spalte 3 Spalte 4 Spalte 5
dies ist ein test nummer 1
und noch ein test nummer 2
schon wieder ein test nummer 3Mit split selber würde es nicht gehen, da jeder Delimiter in einer
Spalte selber vorkommen könnte.bedeutet das das jede Spalte eine fixe Länge hat und keine Tabs drin sind?
Ja genau. Die Datei fülle ich selber mit Daten und ich habe mir
einfach erlaubt, für jede Spalte eine feste Länge zu definieren.
Natürlich hätte ich auch die Daten einfach nebeneinander schreiben
können mit einem Whitespace als Delimiter - in Dateien, bei denen
ein Whitespace in einer Spalte selbst nicht vorkommen würde -,
allerdings müsste ich dann weiterhin mein erstes Beispiel nutzen,
dass leider ab einer bestimmten Größe der Datei sehr lahmt.
Dann würde ich substr verwenden.
Diese Antwort habe ich schon irgendwie erwartet. Ich habe heute
mittag auf irgendeiner Seite gelesen, dass man für mehrere Felder
unpack nutzen sollte. Aber gleichzeitig stand auch dabei, das unpack
um einiges langsamer sein soll als substr. Wann würde es sich also
lohnen, unpack statt substr einzusetzen? Wenn ich nur 5 Felder habe
und 5 mal substr anwende... ok! Aber wie schaut es aus, wenn ich
Beispielsweise 30 Felder zerteilen muss? Würde sich dann eher unpack
lohnen?
Was hälst du denn von meinem zweiten Beispiel? Gibt es eventuell
eine bessere Lösung? Nur her damit :-)
Greez,
opi
oder seek FILE, 0, SEEK_END
das wußte ich noch nicht! Supi!
Im Zweifel gibt es auch eine Dokumentation zu den Modulen. Die von Fnctl ist kurz aber da wird zumindest drauf hingewiesen.
Dann würde ich substr verwenden.
Diese Antwort habe ich schon irgendwie erwartet. Ich habe heute
mittag auf irgendeiner Seite gelesen, dass man für mehrere Felder
unpack nutzen sollte. Aber gleichzeitig stand auch dabei, das unpack
um einiges langsamer sein soll als substr. Wann würde es sich also
lohnen, unpack statt substr einzusetzen? Wenn ich nur 5 Felder habe
und 5 mal substr anwende... ok! Aber wie schaut es aus, wenn ich
Beispielsweise 30 Felder zerteilen muss? Würde sich dann eher unpack
lohnen?Was hälst du denn von meinem zweiten Beispiel? Gibt es eventuell
eine bessere Lösung? Nur her damit :-)
Ich benutze unpack eher selten, kann also dir leider da nicht weiterhelfen.
Aber wenn du Wissen willst was schneller ist dann solltest du dir mal das Benchmark Modul anschauen. Dann kannst du es selber rausfinden, damit hab ich auch schon ein paar Optimierungen gebaut. Wobei das nicht immer leicht ist, da natürlich bei Dateioperationen auch andere Faktoren eine Rolle spielen.
Struppi.
Hallo,
Aber wenn du Wissen willst was schneller ist dann solltest du dir mal das Benchmark Modul anschauen. Dann kannst du es selber rausfinden, damit hab ich auch schon ein paar Optimierungen gebaut. Wobei das nicht immer leicht ist, da natürlich bei Dateioperationen auch andere Faktoren eine Rolle spielen.
Ok. Eine letzte Frage habe ich noch.
Die Datei, die ich auslese, fülle ich mit dem folgendem Beispiel:
Auf Aufteilung der Zeile durch Whitespaces sei mal so dahin
geschrieben...
foreach my $zeile (@$zeilen) {
my $spalten = [ split / /, $zeile ];
foreach my $spalte (@$spalten) {
print FILE "$_" . ' ' x 10-lenght($spalte);
}
print FILE "\n";
}
Auf diese Weise hat jede Spalte eine Länge von 10 Zeichen.
Kann man das so machen oder ist das sehr umständlich?
Greez,
opi
Hallo,
print FILE "$_" . ' ' x 10-lenght($spalte);
print FILE "$spalte" . ' ' x 10-lenght($spalte);
Sorry!
Greez,
opi
Tag opi.
Auf diese Weise hat jede Spalte eine Länge von 10 Zeichen.
Kann man das so machen oder ist das sehr umständlich?
Schau dir mal printf/sprintf an.
Siechfred
Hallo Siechfred,
Schau dir mal printf/sprintf an.
my $string = "test";
print "1234567890\n"
printf '%10s', $string;
print "\n";
Ausgabe ...
1234567890
______test
print "1234567890\n"
printf '%10s', $string;
print "\n";
Ausgabe ...
1234567890
test______
das ist genial und wird bestimmt um einiges schneller laufen als
print + lenght!
Supi! Danke!
Hast du schonmal mit Benchmarks rumgespielt?
Ich würde das gerne mal testen. Kennst du eine gute Doku ausser der
Manpage?
Greez,
opi
Tag opi.
Hast du schonmal mit Benchmarks rumgespielt?
Nicht direkt, nur mit Time::HiRes.
Ich würde das gerne mal testen. Kennst du eine gute Doku ausser der Manpage?
Hm, ich kenne nur Benchmark::Timer, habe es aber selber noch nicht benutzt.
Siechfred
Hallo Siechred,
ich hab mal ein wenig im Archiv rum gesucht und bin auf einen Thread
gestoßen, in dem Struppi mal einen Benchmark ausgeführt hat.
Ich würde das gerne mal testen. Kennst du eine gute Doku ausser der Manpage?
Hm, ich kenne nur Benchmark::Timer, habe es aber selber noch nicht benutzt.
use Benchmark;
my $string = 'string\n';
Benchmark::cmpthese(-1, {
'print' => sub { print "$string" . ' ' x 10-length($string); },
'printf' => sub { printf '%-10s', $string; },
});
Rate print printf
print 127242/s -- -46%
printf 236566/s 86% --
printf ist fast um das doppelte schneller. Mein klarer Favorit :-)
Greez,
opi
Hallo,
use Benchmark;
my $string = 'string\n';
Benchmark::cmpthese(-1, {
'print' => sub { print "$string" . ' ' x 10-length($string); },
'printf' => sub { printf '%-10s', $string; },
});Rate print printf
print 127242/s -- -46%
printf 236566/s 86% --
Sorry, da war ein Syntaxfehler drin:
print "$string" . ' ' x (10-length($string));
Die Ausgabe schaut dann etwas anders aus:
Rate print printf
print 196608/s -- -24%
printf 259646/s 32% --
Aber printf ist noch immer schneller.
Greez,
opi
Hast du schonmal mit Benchmarks rumgespielt?
Ich würde das gerne mal testen. Kennst du eine gute Doku ausser der
Manpage?
Eigentlich reicht die.
Hier mal der vergleich mit DB_File vs. Indexdatei
Wobei ich den code ein bisschen geändert habe, da so die Index datei immer neu eingelesen wird.
Das Ergebniss bei mir mit 10,000 aufrufen:
Benchmark: timing 10000 iterations of DB_File, idx File...
DB_File: 3 wallclock secs ( 2.36 usr + 0.00 sys = 2.36 CPU) @ 4237.29/s (n
=10000)
idx File: 6 wallclock secs ( 5.55 usr + 0.00 sys = 5.55 CPU) @ 1801.80/s (n
=10000)
Rate idx File DB_File
idx File 1802/s -- -57%
DB_File 4237/s 135% --
DB_File ist viel schneller
#!/usr/perl/bin -w
use strict;
package idx_datei;
# usage: build_index(*DATA_HANDLE, *INDEX_HANDLE)
sub build_index
{
my $data_file = shift;
my $index_file = shift;
my $offset = 0;
while (<$data_file>)
{
print $index_file pack("N", $offset);
$offset = tell($data_file);
}
}
# usage: line_with_index(*DATA_HANDLE, *INDEX_HANDLE, $LINE_NUMBER)
# returns line or undef if LINE_NUMBER was out of range
my $entry;
sub line_with_index
{
my $data_file = shift;
my $index_file = shift;
my $line_number = shift;
unless($entry)
{
my $size = length(pack("N", 0));
my $i_offset = $size * ($line_number-1);
seek($index_file, $i_offset, 0) or return;
read($index_file, $entry, $size);
}
my $d_offset = unpack("N", $entry);
seek($data_file, $d_offset, 0);
return scalar(<$data_file>);
}
package main;
use Benchmark;
my $lines = 100;
# idx File
my $file = 'file_idx.txt';
createfile();
open(FILE, "< $file") or die "Can't open $file for reading: $!\n";
open(INDEX, "+> $file.idx")
or die "Can't open $file.idx for read/write: $!\n";
idx_datei::build_index(*FILE, *INDEX);
# DB_File
use DB_File;
use Fcntl;
my $db_file = 'file_db.db';
my @lines;
my $tie = tie(@lines, "DB_File", $db_file, O_RDWR | O_CREAT, 0666, $DB_RECNO)
or die "Cannot open file $db_file: $!\n";
create_db_file();
# Vergleich
my $line;
Benchmark::cmpthese( 10000, {
'idx File' => sub { $line = idx_datei::line_with_index(*FILE, *INDEX, int(rand() * $lines )); },
'DB_File' => sub { $line = $lines[int(rand() * $lines)]; }
});
sub createfile
{
open(FILE, ">$file");
print FILE "$_.". ( 'x' x (rand()*80) ). "\n" for(0...$lines);
close FILE;
}
sub create_db_file
{
$lines[$_] = "$_.". ( 'x' x (rand()*80) ). "\n" for(0...$lines);
}
Struppi.
Tag Struppi.
Hier mal der vergleich mit DB_File vs. Indexdatei [...] DB_File ist viel schneller
Ja, so steht es auch auf der von mir verlinkten Seite.
Siechfred
Tag opi.
Da jede Zeile in der Datei die gleiche Stringlänge hat, benötige ich
die Größe der Datei in Bytes, um an die Richtige Stelle in der Datei
mit seek springen zu können.
Du könntest dir auch eine Indexdatei anlegen, mit deren Hilfe es problemlos möglich wäre, an eine bestimmte Stelle der Textdatei zu springen.
Wie splitte ich am besten jede Zeile in ihre Einzelstrings? Mit substr oder unpack?
Vielleicht funktioniert ja auch split mit einem entsprechenden Suchmuster.
Siechfred
Hallo Siechfred,
Tag opi.
Da jede Zeile in der Datei die gleiche Stringlänge hat, benötige ich
die Größe der Datei in Bytes, um an die Richtige Stelle in der Datei
mit seek springen zu können.Du könntest dir auch eine Indexdatei anlegen, mit deren Hilfe es problemlos möglich wäre, an eine bestimmte Stelle der Textdatei zu springen.
Meinst du eine zusätzliche Datei die bei jedem Append gepflegt wird?
Zum Beispiel:
datei.txt
datei_index.txt
In datei_index.txt steht dann immer der aktuelle Byte-Wert der
Position, zu ich gerne springen möchte? Das wäre eine Überlegung
wert. Diesen Wert könnte ich auch in der ersten Zeile von datei.txt
ablegen mit einer festen Länge, zum Beispiel
zeile30=000000030043
Oder meinst du in der datei.txt vor jeder Zeile einen Wert abzulegen?
Hierfür müsste ich trotzallem die Datei bis zu der Position durchlesen
und den Index auswerten, was mir zu lange dauert.
Greez,
opi
Tag opi.
Du könntest dir auch eine Indexdatei anlegen, mit deren Hilfe es problemlos möglich wäre, an eine bestimmte Stelle der Textdatei zu springen.
Meinst du eine zusätzliche Datei die bei jedem Append gepflegt wird?
So in etwa. Eine ziemlich schnelle Lösung mit Index-Datei findest du hier:
http://www.unix.org.ua/orelly/perl/cookbook/ch08_09.htm
Das Einzige, das etwas dauert, ist das erstmalige Generieren der Index-Datei. Dann aber flutscht das Programm so richtig :-)
Siechfred
Hello again,
Spalte 1 Spalte 2 Spalte 3 Spalte 4 Spalte 5
dies ist ein test nummer 1
und noch ein test nummer 2
schon wieder ein test nummer 3Mit split selber würde es nicht gehen, da jeder Delimiter in einer
Spalte selber vorkommen könnte.
ich war nochmal so frei und habe getestet, ob sich eine Datei, in der
die Daten in Tabellenform mit fester Stringlänge abgelegt werden
auch wirklich lohnt oder ob ich einen beliebigen Delimiter als
Trennzeichen nutze und die Daten einfach mit split oder etwas
anderem aufteile.
Mein Resultat ist, dass substr in jedem Fall schneller ist und das
sich eine Datendatei in Tabellenform mit fester Stringlänge in jedem
Fall lohnt.
Ob so:
my $string = "string0 string1 string2 string3 string4 string5 string6 string7 string8 string9 ";
Benchmark::cmpthese(-1, {
'substr' => sub { my $f0 = substr($string, 0, 10);
my $f1 = substr($string, 11, 10);
my $f2 = substr($string, 21, 10);
my $f3 = substr($string, 31, 10);
my $f4 = substr($string, 41, 10);
my $f5 = substr($string, 51, 10);
my $f6 = substr($string, 61, 10);
my $f7 = substr($string, 71, 10);
my $f8 = substr($string, 81, 10);
my $f9 = substr($string, 91, 10);
},
'split' => sub { my ($f0, $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8, $f9) = split /\s+/, $string; },
'regexp' => sub { $string =~ /^(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+$/;
my $f0 = $1;
my $f1 = $2;
my $f2 = $3;
my $f3 = $4;
my $f4 = $5;
my $f5 = $6;
my $f6 = $7;
my $f7 = $8;
my $f8 = $9;
my $f9 = $10;
},
});
Benchmark: running regexp, split, substr for at least 1 CPU seconds...
regexp: 1 wallclock secs ( 1.00 usr + 0.06 sys = 1.06 CPU) @ 40572.64/s (n=43007)
split: 1 wallclock secs ( 1.02 usr + 0.03 sys = 1.05 CPU) @ 51199.05/s (n=53759)
substr: 1 wallclock secs ( 1.04 usr + 0.04 sys = 1.08 CPU) @ 99554.63/s (n=107519)
Rate regexp split substr
regexp 40573/s -- -21% -59%
split 51199/s 26% -- -49%
substr 99555/s 145% 94% --
Oder so:
my $string1 = "string0 string1 string2 string3 string4 string5 string6 string7 string8 string9 ";
my $string2 = "string0 string1 string2 string3 string4 string5 string6 string7 string8 string9";
Benchmark::cmpthese(-1, {
'substr' => sub { my $f0 = substr($string1, 0, 10);
my $f1 = substr($string1, 11, 10);
my $f2 = substr($string1, 21, 10);
my $f3 = substr($string1, 31, 10);
my $f4 = substr($string1, 41, 10);
my $f5 = substr($string1, 51, 10);
my $f6 = substr($string1, 61, 10);
my $f7 = substr($string1, 71, 10);
my $f8 = substr($string1, 81, 10);
my $f9 = substr($string1, 91, 10);
},
'split' => sub { my ($f0, $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8, $f9) = split /\s+/, $string2; },
'regexp' => sub { $string2 =~ /^(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+$/;
my $f0 = $1;
my $f1 = $2;
my $f2 = $3;
my $f3 = $4;
my $f4 = $5;
my $f5 = $6;
my $f6 = $7;
my $f7 = $8;
my $f8 = $9;
my $f9 = $10;
},
});
}
Benchmark: running regexp, split, substr for at least 1 CPU seconds...
regexp: 2 wallclock secs ( 1.22 usr + 0.03 sys = 1.25 CPU) @ 21504.00/s (n=26880)
split: 1 wallclock secs ( 1.03 usr + 0.02 sys = 1.05 CPU) @ 54613.33/s (n=57344)
substr: 2 wallclock secs ( 1.03 usr + 0.06 sys = 1.09 CPU) @ 98642.20/s (n=107520)
Rate regexp split substr
regexp 21504/s -- -61% -78%
split 54613/s 154% -- -45%
substr 98642/s 359% 81% --
Greez,
opi
Hallo,
oh je, ich nehme alles wieder zurück!
Ich habe ganz vergessen, dass nach dem substr ja auch noch die
Leerzeichen weggeschnitten werden müssen, die am Ende des Strings
vorkommen könnten.
Somit ist mein Beispiel hinfällig!
my $string = "string0 string1 string2 string3 string4 string5 string6 string7 string8 string9 ";
Benchmark::cmpthese(-1, {
'substr' => sub { my $f0 = substr($string, 0, 10);
my $f1 = substr($string, 11, 10);
my $f2 = substr($string, 21, 10);
my $f3 = substr($string, 31, 10);
my $f4 = substr($string, 41, 10);
my $f5 = substr($string, 51, 10);
my $f6 = substr($string, 61, 10);
my $f7 = substr($string, 71, 10);
my $f8 = substr($string, 81, 10);
my $f9 = substr($string, 91, 10);
},
'split' => sub { my ($f0, $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8, $f9) = split /\s+/, $string; },
'regexp' => sub { $string =~ /^(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+$/;
my $f0 = $1;
my $f1 = $2;
my $f2 = $3;
my $f3 = $4;
my $f4 = $5;
my $f5 = $6;
my $f6 = $7;
my $f7 = $8;
my $f8 = $9;
my $f9 = $10;
},
});Benchmark: running regexp, split, substr for at least 1 CPU seconds...
regexp: 1 wallclock secs ( 1.00 usr + 0.06 sys = 1.06 CPU) @ 40572.64/s (n=43007)
split: 1 wallclock secs ( 1.02 usr + 0.03 sys = 1.05 CPU) @ 51199.05/s (n=53759)
substr: 1 wallclock secs ( 1.04 usr + 0.04 sys = 1.08 CPU) @ 99554.63/s (n=107519)
Rate regexp split substr
regexp 40573/s -- -21% -59%
split 51199/s 26% -- -49%
substr 99555/s 145% 94% --
Nun habe ich es mal das Wegschneiden der Whitespaces hinzugenommen:
my $string = "string0 string1 string2 string3 string4 string5 string6 string7 string8 string9 ";
Benchmark::cmpthese(-1, {
'substr' => sub { (my $f0 = substr($string, 0, 10)) =~ s/\s+$//;
(my $f1 = substr($string, 11, 10)) =~ s/\s+$//;
(my $f2 = substr($string, 21, 10)) =~ s/\s+$//;
(my $f3 = substr($string, 31, 10)) =~ s/\s+$//;
(my $f4 = substr($string, 41, 10)) =~ s/\s+$//;
(my $f5 = substr($string, 51, 10)) =~ s/\s+$//;
(my $f6 = substr($string, 61, 10)) =~ s/\s+$//;
(my $f7 = substr($string, 71, 10)) =~ s/\s+$//;
(my $f8 = substr($string, 81, 10)) =~ s/\s+$//;
(my $f9 = substr($string, 91, 10)) =~ s/\s+$//;
},
'split' => sub { my ($f0, $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8, $f9) = split /\s+/, $string; },
'regexp' => sub { $string =~ /^(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+$/;
my $f0 = $1;
my $f1 = $2;
my $f2 = $3;
my $f3 = $4;
my $f4 = $5;
my $f5 = $6;
my $f6 = $7;
my $f7 = $8;
my $f8 = $9;
my $f9 = $10;
},
});
Benchmark: running regexp, split, substr for at least 1 CPU seconds...
regexp: 2 wallclock secs ( 0.93 usr + 0.07 sys = 1.00 CPU) @ 40325.00/s (n=40325)
split: 1 wallclock secs ( 0.97 usr + 0.06 sys = 1.03 CPU) @ 45983.50/s (n=47363)
substr: 1 wallclock secs ( 1.07 usr + 0.02 sys = 1.09 CPU) @ 41533.03/s (n=45271)
Rate regexp substr split
regexp 40325/s -- -3% -12%
substr 41533/s 3% -- -10%
split 45983/s 14% 11% --
und siehe da... die substr Variante wird natürlich langsamer.
Kann ich da noch etwas Tunen? Eventuell einen Ersatz für das
Schneiden mittels s/\s+$// ???
Greez,
opi
Tag opi.
Kann ich da noch etwas Tunen?
Ja, einen RegExp im Listenkontext, der liefert mir hier das beste Ergebnis:
Benchmark::cmpthese(-1, {
'substr' => sub { (my $f0 = substr($string, 0, 10)) =~ s/\s+$//;
(my $f1 = substr($string, 11, 10)) =~ s/\s+$//;
(my $f2 = substr($string, 21, 10)) =~ s/\s+$//;
(my $f3 = substr($string, 31, 10)) =~ s/\s+$//;
(my $f4 = substr($string, 41, 10)) =~ s/\s+$//;
(my $f5 = substr($string, 51, 10)) =~ s/\s+$//;
(my $f6 = substr($string, 61, 10)) =~ s/\s+$//;
(my $f7 = substr($string, 71, 10)) =~ s/\s+$//;
(my $f8 = substr($string, 81, 10)) =~ s/\s+$//;
(my $f9 = substr($string, 91, 10)) =~ s/\s+$//;
},
'split' => sub { my @fn = split /\s+/, $string; },
'regexp' => sub { my @fn = $string =~ /(\w+?\d)/g; },
});
Ergibt:
Rate regexp substr split
regexp 24325/s -- -51% -52%
substr 49320/s 103% -- -2%
split 50242/s 107% 2% --
Siechfred
Hallo,
Tag opi.
Kann ich da noch etwas Tunen?
Ja, einen RegExp im Listenkontext, der liefert mir hier das beste Ergebnis:
Benchmark::cmpthese(-1, {
'substr' => sub { (my $f0 = substr($string, 0, 10)) =~ s/\s+$//;
(my $f1 = substr($string, 11, 10)) =~ s/\s+$//;
(my $f2 = substr($string, 21, 10)) =~ s/\s+$//;
(my $f3 = substr($string, 31, 10)) =~ s/\s+$//;
(my $f4 = substr($string, 41, 10)) =~ s/\s+$//;
(my $f5 = substr($string, 51, 10)) =~ s/\s+$//;
(my $f6 = substr($string, 61, 10)) =~ s/\s+$//;
(my $f7 = substr($string, 71, 10)) =~ s/\s+$//;
(my $f8 = substr($string, 81, 10)) =~ s/\s+$//;
(my $f9 = substr($string, 91, 10)) =~ s/\s+$//;
},
'split' => sub { my @fn = split /\s+/, $string; },
'regexp' => sub { my @fn = $string =~ /(\w+?\d)/g; },
});
>
> Ergibt:
>
> Rate regexp substr split
> regexp 24325/s -- -51% -52%
> substr 49320/s 103% -- -2%
> split 50242/s 107% 2% --
wie kommst du darauf, dass regexp mit 24325 Iterations pro Sekunde
das beste Ergebnis liefert? Für mich ist split noch am schnellsten
mit 50242 Iterations pro (CPU-) Sekunde.
Oder irre ich mich an dieser Stelle etwa?
Greez,
opi
--
Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
Tag opi.
wie kommst du darauf, dass regexp mit 24325 Iterations pro Sekunde
das beste Ergebnis liefert? Für mich ist split noch am schnellsten
mit 50242 Iterations pro (CPU-) Sekunde.
Nee, du hast schon Recht ... war wohl ein bisschen zu viel heute :-)
Siechfred
Hallo,
wie kommst du darauf, dass regexp mit 24325 Iterations pro Sekunde
das beste Ergebnis liefert? Für mich ist split noch am schnellsten
mit 50242 Iterations pro (CPU-) Sekunde.Nee, du hast schon Recht ... war wohl ein bisschen zu viel heute :-)
für mich war das auch mal wieder ein langer Tag, aber zum Glück ist
morgen Freitag - obwohl ich auch nicht besonders viel vom WE haben
werde.
Um nochmal auf meine Frage zu kommen... hast du etwas "schnelleres"
als s/\s+$// parat bezüglich der Zerteilung eines Strings mit substr,
damit ich split toppen kann?
Ich müsste mir printf und sprintf nochmal anschauen, denn wenn die
Ausgabe einer festen Stringlänge mittels printf '%-10s' funktioniert,
dann gibt es doch auch bestimmt etwas in die andere Richtung, um den
String ohne Leerzeichen zu filtern. Ich muss mal stöbern...
Gutes nächtle ansonsten... vielleicht schau ich später nochmal rein!
Greez,
opi
Hallo Siechfred,
dann gibt es doch auch bestimmt etwas in die andere Richtung, um den
String ohne Leerzeichen zu filtern. Ich muss mal stöbern...
nun ich habe nichts anderes gefunden, als mit regexp die
Leerzeichen zu entfernen.
Meine endgültigen Lösungen sind also:
my $string = "string 0 string 1 string 2 string 3 string 4 string 5 string 6 string 7 string 8 string 9 ";
Benchmark::cmpthese(-1, {
'substr' => sub { (my $f0 = substr($string, 0, 10)) =~ s/\s+$//;
(my $f1 = substr($string, 11, 10)) =~ s/\s+$//;
(my $f2 = substr($string, 21, 10)) =~ s/\s+$//;
(my $f3 = substr($string, 31, 10)) =~ s/\s+$//;
(my $f4 = substr($string, 41, 10)) =~ s/\s+$//;
(my $f5 = substr($string, 51, 10)) =~ s/\s+$//;
(my $f6 = substr($string, 61, 10)) =~ s/\s+$//;
(my $f7 = substr($string, 71, 10)) =~ s/\s+$//;
(my $f8 = substr($string, 81, 10)) =~ s/\s+$//;
(my $f9 = substr($string, 91, 10)) =~ s/\s+$//;
},
'unpack1' => sub { my $field = [ map /^(.+?)\s+$/, unpack ("a10a10a10a10a10a10a10a10a10a10",$string) ]; },
'unpack2' => sub { my ($f0, $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8, $f9) = unpack ("a10a10a10a10a10a10a10a10a10a10",$string);
$f0 =~ s/\s+$//;
$f1 =~ s/\s+$//;
$f2 =~ s/\s+$//;
$f3 =~ s/\s+$//;
$f4 =~ s/\s+$//;
$f5 =~ s/\s+$//;
$f6 =~ s/\s+$//;
$f7 =~ s/\s+$//;
$f8 =~ s/\s+$//;
$f9 =~ s/\s+$//;
},
'split' => sub { my $field = [ map /^(.+?)\s+$/, split /(.{10})/, $string ]; },
'regexp1' => sub { my $field = [ map /^(.+?)\s+$/, $string =~ /(.{10})/g ]; },
'regexp2' => sub { my $field = [ map /^(.+?)\s+$/, $string =~ /(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})/ ]; }
});
Rate split2 regexp2 regexp1 unpack1 unpack2 substr
split 25373/s -- -12% -16% -21% -66% -71%
regexp2 28709/s 13% -- -5% -11% -61% -67%
regexp1 30351/s 20% 6% -- -6% -59% -65%
unpack1 32288/s 27% 12% 6% -- -57% -62%
unpack2 74472/s 194% 159% 145% 131% -- -14%
substr 86102/s 239% 200% 184% 167% 16% --
split und regexp1 fallen weg, falls Spalten unterschiedliche
Längen haben sollten.
substr wäre die schnellste Variante.
Greez,
opi
Rate split2 regexp2 regexp1 unpack1 unpack2 substr
split 25373/s -- -12% -16% -21% -66% -71%
regexp2 28709/s 13% -- -5% -11% -61% -67%
regexp1 30351/s 20% 6% -- -6% -59% -65%
unpack1 32288/s 27% 12% 6% -- -57% -62%
unpack2 74472/s 194% 159% 145% 131% -- -14%
substr 86102/s 239% 200% 184% 167% 16% --
Hehe, macht Spaß mit Benchmark rumzuspielen gerade wenn man kleinere Routinen optimieren möchte.
Struppi.
Hallo,
Hehe, macht Spaß mit Benchmark rumzuspielen gerade wenn man kleinere Routinen optimieren möchte.
ja, es macht echt Spaß. Seit zwei Tagen mache ich nichts
anderes, als meine Skripts zu Tunen, dies und jenes aus-
zuprobieren. Es ist erstaunlich, wo man alles etwas rausholen
kann :-)
Greez,
opi