[linux-l] Ruby: sehr cool, aber auch sehr laaaahm... wie geht's schneller?!

Oliver Bandel oliver at first.in-berlin.de
Di Aug 22 19:50:33 CEST 2006


Moin,


On Tue, Aug 22, 2006 at 10:43:25AM +0200, Steffen Dettmer wrote:
> * Oliver Bandel wrote on Mon, Aug 21, 2006 at 13:48 +0200:
> > Das wird aber auch nicht schneller.... sollte es aber,
> > denn die Datei dürfte ja nach dem throw nicht mehr zuende gelesen
> > werden müssen. 
> 
> Wie gross sind die Files? So eher klein? Dann würde mich das nicht
> überraschen, denn vermutlich wird da eh blockweise gecacht etc. 3
> Sekunden ist natürlich fett... Sind das viele kleine oder wenige grosse
> Dateien?

Hatte ich bereits mal geschrieben: 188 Dateien mit insgesamt ca. 16 MB.


> 
> Ist aber witzig, dass es bei Abbruch nicht schneller wird, find ich auch
> spannend :-)
> 

Naja, witzig finde ich das nicht, sondern seltsam und nervig. :(



> > Allerdings sagen mir die Ausführungszeiten, daß anscheinend doch alle
> > Files bis zum bitteren Ende gelesen werden...?!
> 
> strace hilft bei solchen Fragen manchmal.

Hmhhh. Naja, vielleicht macht das sogar Sinn...
...ma kieken.




> 
> > Perl-Version zum Vergleich:
> > ---------------------------
> > 
> > 
> > ========================================
> >   foreach (@ARGV)
> >   {
> >     open FILE, "$_"  or next;
> >     while(<FILE>)
> >     {
> >       if( /^begin/ )
> >       {
> >         print;
> >         #close FILE;
> >         #next;
> >       }
> >     }
> >     close FILE;
> >   }
> > ========================================
> > 
> > ca. 1,7 Sekunden mit den Kommentaren,
> > ca. 0,8 Sekunden wenn man die Kommentarzeichen entfernt
> 
> Na ja, also mit Zeiten muss man sehr aufpassen... Bei mir dauert Dein
> Beispiel:
> 
> steffen at link:~/5> time ./test.pl *rar
> 
> real    0m2.457s
> user    0m0.370s
> sys     0m0.170s
> steffen at link:~/5> time ./test.pl *rar
> 
> real    0m0.488s
> user    0m0.300s
> sys     0m0.180s
> 
> direkt hintereinander, schlägt OS Cache natürlich zu :)

Ja, ich weiss.
Ich habe die Werte, die ich angegeben habe auch immer durch mehrfaches
Ausführen ermittelt.
Eigentlich dürfte man das ja nicht und müsste bei allen malen
immer einen ersten Fall haben, denn im Allgemeinen führt man die Programme
ja nicht mehrfach hintereinander aus, nur um dann beim letzten Ausführen
schneller fertig zu sein ;-)
Aber wie will man es sonst testen?
=> Also bei allen SpeedTests mehrfach ausführen und dann den Mittelwert
der letzten Ausführungen (oder alle ausser dem ersten) nehmen.

Aber wenn Du das Script da oben nimmst und die Kommentarzeichen entfernst,
sollte es erheblich schneller werden, falls das Pattern kurz hinter dem
Header der Mail/des Postings zu finden ist.



> 
> Das oben funktioniert, weil "while(<FILE>)" mit Fehler zurückkommt, wenn
> das "#next" auf der geschlossenen Datei liest und "fertig" ist?

Die Sache mit dem "next" (das next hinter dem "open") dient dazu, bei unsinnigem Filenamen
nicht in Probleme zu rasseln; üblich ist es ja, mit "die" eine
Fehlermeldung auszugeben und das Programm abzubrechen; aber hier fand
ich es sinnvoller, stattdessen Filenamen, die unsinng sind, oder die
zu Files gehören, die man nicht lesen kann, einfach zu ignorieren
und dann mit dem nächsten Filenamen weiter zu machen.

"#next" ist ein auskommentiertes "next".
Es funktioniert also garnicht.
Ebenso ist es mit "#close FILE".






> 
> Würde statt dem close/next lieber einfach ein last oder ein break
> nehmen, oder dem foreach ein label file oder so ("FILE: foreach(x))
> geben und dann mit next FILE; anspringen.

Stimmt, man kann mit last arbeiten; ich hatte das aber so geschrieben,
weil ich das an den Ruby-Sourcen entlang geschrieben habe, also möglichst
ähnllich formulierte.


> 
> 
> Zu der Performance: ja, geh davon aus, dass stringvergleiche schneller
> sind als regex, ABER wenn man z.B. 

Eben.

Bei simplen Patterns kann es aber sein, daß der Unterschied nicht so sehr drastisch ist.


>   /^begin/ 
> mit
>   str.strstr("begin") == 0
> abbildet (also "Sub-String-Suche"), wirds natürlich langsam. Wenn begin
> nicht drin ist, muss strstr den ganzen String durchsuchen (könnte ja an
> index 10341231 noch ein begin kommen).

Deswegen hatte ich in der OCaml-Version den Anfang des Strings direkt verglichen
und nicht nach einem Substring gesucht.


> Der RegEx kann optimieren, wenn's
> halt nicht am Anfang war und muss nicht weitersuchen, strstr weiss das
> aber ja nicht. Dann lieber substr auf strlen des "begin" und "eq" oder
> strcmp Vergleiche mit dem Ergebnis, strncmp sollte hier noch schneller
> sein, wenn man es hat. Sowas ist dann eigentlich immer sehr schnell, es
> "fasst keine nicht benötigen Bytes an", bei langen Zeilen hier natürlich
> sehr wichtig. Ich glaub, schneller kriegt man das dann nicht.

*Äääähem*, *Räääuüüüspeer*, ... ich wollte nicht am Perl optimieren,
sondern am Ruby....


> 
> Das langsame kommt dann wieder vom "gets" oder was man da nimmt, das
> muss mindestens newlines suchen.

In der C-Variante hatte ich fgets() genommen; aber mit max. 10000 Zeichen
Buffersize. OK, hätte ich auch kürzer machen können (so lang wie der Keyword-String),
aber dann hätte man ja evtl. etliche Aufrufe, wenn das nächste "\n" noch lange
auf sich warten lässt....

.... Ich könnte auch sagen: Nach Ende des Headers suche maximal
50 Zeilen und wenn das Keyword nicht gefunden wurde, gib auf,
es wird nicht ein solches File sein.

Naja, dieses ganze Optimierungszeugs wollte ich aber erst mal
nicht machen.

Ich hatte so ein Tool schon mal angefangen, aber das dann nicht weiter
verfolgt. (Naja, wenn jemand das finanziert hätte, wäre es wohl schon
fertig ;-))

Ich wollte eigentlich, wenn es Programmierung at home ist,
es recht einfach halten. Darum auch mal mit Ruby, das da recht luxuriöse
Syntax und Libs anbietet, nehmen und mal nebenbei ein bischen was bauen.

Da ich gerade wieder in einem Umzug stecke und die letzten Wochen Dielen geschliffen
habe, sitz ich Abends eh mit Staub auf den Pupillen am Rechner ;-)
Und wenn man den dann Abends (wie es sich für einen ordentlichen Dielenschleifer
so gehört;-)) den Staub mit nem Bier runter spült, ist's einem egal,
ob man bei einer Sprache, die man garnicht einsetzen will noch optimieren kann.
Ich wollte doch bloß etwas Ruby machen.... aber das sollte sich doch bitteschön
wenigstens auch ein *bischen* optimieren lassen....



> Kann man aber geschickt (mit caching
> etc) implementieren. Ich würde immer erwarten, dass sowas schnell
> implementiert ist.

Ich will, wenn ich ein paar Helfer-Tools mir baue nicht drei Jahre lang
dran entwickeln ;-)

Wenn das meine Brötchen finanzieren würde, wäre das was anderes.
Aber selbst dann mag ich es eher schnell Lösungen zu bringen;
optimieren kann man immernoch.
So habe ich das hier ja auch handhaben wollen: Wenn es mit ein paar
Zeilen Ruby geht (das ich mir ja nun drauf zimmern wollte), dann eben so,
statt mit anderen Sprachen Umwege zu gehen.
Nur, daß das Verhalten von dem Rubin reichlich neben der Spur lag. :(

Ein bischen an gängiges Laufzeitverhalten sollte es sich bitte schon halten...


...ausser, Ruby braucht auch bei 10 und auch bei 100 mal so vielen/großen
Files immernoch 3,6 Sekunden.... vielleicht geht das dann ja auch bei
10 GB und 120 TB?!

Wenn das dann auch noch bei allen möglichen Algorithmen/Anwendungsfällen geht,
kann ich jedes Rechenzentrum platt machen ;-)

"Hurraa, hurraa, egal was immer ich auch berechne, ich schaffe es in 3,6 Sekunden!" :)



> 
> Unterm Strich würde ich raten, dass es am schnellsten sein sollte,
> "\nbegin" im File-input zu suchen.

Ich suche nicht die allerschnellste Lösung, ich wollte bloß wissen,
wieso das Ruby-Script sich so seltsam verhält.... *heul* ;-)


> 
> > So etwas (speedup) hätte ich bei meinen Ruby-Lösungen auch erwartet.
> 
> Ja, komisch...
> 

Ha, ha, ha, :( wenn Du nochmal "komisch" sagst, fange ich noch an zu lachen... ;-(

Gruß,
   Oliver




Mehr Informationen über die Mailingliste linux-l