Seite 1 von 2

Speedtests: MeinString$="" vs. Len(MeinString$)=0

Verfasst: 19.08.2005 12:08
von Kiffi
Hallo

hiermit möchte ich einen Thread eröffnen, in dem es darum geht,
verschiedene Programmiertechniken gegenüberzustellen und sie in Bezug
auf deren Geschwindigkeit zu untersuchen. Ich fange mal mit einem
einfachen Beispiel an:

Es kommt nicht gerade selten vor, dass ein Programmierer testen muss,
ob ein String einen Inhalt hat oder leer ist. Normalerweise geschieht dies
mit einem Vergleich auf einen Leerstring:

Code: Alles auswählen

; Variante 1
If MeinString$ = ""
ebenso könnte man auch testen, ob der String eine Länge von 0 hat. Dann
ist er ebenfalls leer:

Code: Alles auswählen

; Variante 2
If Len(MeinString$) = 0
VB-Programmierer werden vermutlich wissen, dass in Ihrer Sprache
Variante 2 die eindeutig schnellere ist, denn VB generiert in Variante 1
zunächst einen Leerstring, um ihn dann mit MeinString$ zu vergleichen.
Diese zeitaufwendige Stringgenerierung fällt in Variante 2 weg.

Doch wie sieht's in PB aus. Welche Variante ist hier zu bevorzugen?

Um das Ergebnis vorwegzunehmen: Variante 1 ist in diesem Vergleich der
klare Geschwindigkeitssieger. Und: je länger der zu testende String ist,
desto deutlicher wird der Zeitunterschied.

Code: Alles auswählen

; Speedtest 1
; Prüfung, ob String leer ist

NewList ST_Check_1.l()
NewList ST_Check_2.l()

sDummy$ = Space(255)

For Schleife = 0 To 20

  ; ##################################
  ; Prüfung mittels Len(MeinString) = 0
  ; ##################################
  
  Z1 = ElapsedMilliseconds()
  
  For Counter = 0 To 1000000
    If Len(sDummy$)=0 : EndIf
  Next Counter
  
  Z2 = ElapsedMilliseconds()
  
  AddElement(ST_Check_1()) : ST_Check_1()=Z2-Z1
  
  ; ##################################
  ; Prüfung mittels MeinString = ""
  ; ##################################
  
  Z1 = ElapsedMilliseconds()
  
  For Counter = 0 To 1000000
    If sDummy$="" : EndIf
  Next Counter
  
  Z2 = ElapsedMilliseconds()
  
  AddElement(ST_Check_2()) : ST_Check_2()=Z2-Z1

Next

; ##################################
; Prüfung abgeschlossen
; hier kommt die Ausgabe:
; ##################################

sMessage$ = ""

For Schleife = 0 To 20
  
  SelectElement(ST_Check_1(), Schleife)
  SelectElement(ST_Check_2(), Schleife)
  
  sMessage$ + Str(ST_Check_1()) + " / " + Str(ST_Check_2()) + #CRLF$
  
Next

MessageRequester("", sMessage$)
Grüße ... Kiffi

Verfasst: 19.08.2005 12:23
von bobobo
Es ist mir irgendwie leicht reinlaufend, dass ne Funktion irgendwie lahmer ist als ne direkte Zuweisung. Ich fahr doch auch nicht von Bielefeld nach Brackwede über Berlin. Bin aber auch nicht VB. :D

Verfasst: 19.08.2005 13:10
von Eric
Ich hab eine noch etwas schnellere Variante gebastelt: (bei mir etwa 3*so schnell wie Variante 1)

Code: Alles auswählen

;Variante 3
!mov eax,[v_MeinString$]
!cmp byte [eax],0 ;If MeinString$=""
!jne @f
;Hier kommt dann der Code rein, der ausgeführt wird, wenn MeinString$="" ist
!@@: ;EndIf
Ich hoffe mal, dass es mir PB nicht übel nimmt, wenn ich ihm ein Register entwende /:->

Ich kann auch noch ne Variante mit Else basteln, wird nur etwas umständlicher mit den anonymen Labels.

Noch ne kleine Anmerkung:
Durch die anonymen Labels lassen sich die dinger nicht ohne weiteres verschachteln, man müsste also das @@ und das @f durch etwas anderes ersetzen.

Verfasst: 19.08.2005 14:44
von Deeem2031
bobobo hat geschrieben:Es ist mir irgendwie leicht reinlaufend, dass ne Funktion irgendwie lahmer ist als ne direkte Zuweisung. Ich fahr doch auch nicht von Bielefeld nach Brackwede über Berlin. Bin aber auch nicht VB. :D
If sDummy$="" generiert auch einen Procedureaufruf (SYS_StringEqual) und da SYS_StringEqual und PB_Len den Stack nicht benutzen wird es am Aufruf nicht liegen. Es liegt allein daran das PB_Len nicht so gut optimiert wie SYS_StringEqual ist.

[Edit] Ich bin davon ausgegangen das der String leer ist, ist er nicht leer ist SYS_StringEqual in jedem Fall schneller, da PB_Len den ganzen String durchgehen muss, SYS_StringEqual aber nur das erste Byte vergleichen muss.

Verfasst: 21.08.2005 19:15
von Sylvia
Anstatt

Code: Alles auswählen

If sDummy$=""
sollte man lieber nur

Code: Alles auswählen

If sDummy$
als Umkehrabfrage schreiben (ca.3x schneller), sofern es der Übersichtlich- und
Verständlichkeit des Codes nicht abträglich ist


Allerdings ist

Code: Alles auswählen

If Len(sDummy$)=0
statt diese Umkehrvariante

Code: Alles auswählen

If Len(sDummy$)
kaum messbar langsamer, weil keine echte Stringbehandlung erfolgt

Verfasst: 21.08.2005 21:54
von Batze
Ich würde auch sagen

Code: Alles auswählen

If String$
Denn schließlich ist dann nur die Adresse auszulesen, die bei Leerstrings immer 0 ist.

Verfasst: 21.08.2005 23:03
von Deeem2031
Batze hat geschrieben:Ich würde auch sagen

Code: Alles auswählen

If String$
Denn schließlich ist dann nur die Adresse auszulesen, die bei Leerstrings immer 0 ist.
Das meinst du doch nicht ernst oder? Ein NullString hat doch keinen NullPointer..

Verfasst: 22.08.2005 11:08
von Batze
Oh, das hab ich ja wirklich so geschrieben. :shock: :oops: :freak:
Ich meinte eigentlich nicht das die Adresse 0 ist sondern der Byte-Wert den man an der Adresse auslesen kann.
Ich denke - oder hoffe zumindest - dass PureBasic dann nur das eine Byte ausliest.

Verfasst: 30.08.2005 14:34
von hardfalcon
ICh hab bisher sowieso immer Sylvias Methode benutzt. (Ich wusste zwar nicht, dass sie schneller ist, aber es ist immerhin weniger zu tippen, und ich bin halt ein fauler Sack... :mrgreen: )
Mich würde mal interessieren, was schneller ist: If - ElseIf - Else - EndIf oder Select - Case - Default - EndSelect ? Aber da ich ein fauler Sack bin, kann ich mich grade nicht dazu durchringen das zu testen. Ich vermute mal, beides ist gleich schnell, sprich es wird der gleiche ASM-Code dafür generiert, es wird nur unter PB anders geschrieben... :lol:

Verfasst: 30.08.2005 15:25
von NicTheQuick
Ich denke, dass es anders ist.

Bei ElseIf kann man wieder eine ganz andere Bedingung angeben wie bei Select.
Bei Select wird der zu überprüfende Wert sicherlich nur einmal in ein Register geschoben und dann mit jedem Wert hinter Case verglichen bis ein Treffer gefunden wurde.
Hinter ElseIf kann man jedesmal zwei andere Variablen, Konstanten oder was weiß ich miteinander vergleichen. Und ich denke, dass PureBasic dahingehend noch nicht so weit optimiert.

Aber da ich mich mit ASM nicht gerne auseinandersetze, kann das gerne mal jemand anderes testen.