Seite 1 von 3

Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 11:14
von dysti
Ich hatte immer gedacht, das Pointerversionen in der Verarbeitung immer schneller sind.
Das scheint nicht grundsätzlich so zu sein oder ist die nur nicht auf Schnelligkeit optimiert worden?
Die Variante 1 braucht 530ms, die Pointerversion braucht 1123ms, also fast doppelt so lange!
Wie würde die schnellste optimierte Variante aussehen?

Code: Alles auswählen

Macro ErsetzeString2(String,pos,laenge,ersatz)
  Left(String,pos-1)+ersatz+Mid(String,pos+laenge)
EndMacro
Macro ErsetzeString3(String , pos , laenge , Ersatz)
  len_original = Len(PeekS(@String)) * SizeOf(Character)
  l1 = pos+laenge-1
  len_rest     = len_original - l1
  b$=PeekS(@String,pos-1) + Ersatz + PeekS(@String+l1, len_rest)
EndMacro

; --------------------

; Der Originalsatz
a$="Das war einmal der Satz"
Debug a$
Debug ""
; Das hier, weil ich zu faul zum selber Zaehlen bin
; und weil Änderungen ja später vom Prg. generiert werden könnten
lmax = Len(a$)
alt$ = "war einmal"
neu$ = "ist nun"
pos = FindString(a$,alt$)
laenge = Len(alt$)

; Ein Füllzeichen, wenn der Str. seine Länge behalten soll.
fuell$="."

; Nun der neue Satz 1, es ist laut Ausgabe der Schnellere
zeit=ElapsedMilliseconds()
For i=1 To 1000000
  b$=ErsetzeString2(a$,pos,laenge,neu$)
Next
Debug "Zeit 2 = "+Str(ElapsedMilliseconds()-zeit)+" MilliSek."
Debug b$
Debug LSet(b$ ,lmax,fuell$)
Debug RSet(b$ ,lmax,fuell$)
Debug ""

; Nun der neue Satz 2
zeit=ElapsedMilliseconds()
For i=1 To 1000000
ErsetzeString3(a$,pos,laenge,neu$)
Next
Debug "Zeit 3 = "+Str(ElapsedMilliseconds()-zeit)+" MilliSek."
Debug b$
Debug LSet(b$ ,lmax,fuell$)
Debug RSet(b$ ,lmax,fuell$)
Debug ""

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 11:45
von STARGÅTE
Erstens: Zeitvergleiche werden OHNE Debugger durchgeführt. Dein Resultat ist also nutzlos.
Zweitens hat deine zweite Variante nix mit Pointern zu tun. Du nutzt ja trotzdem PB Funktionen zum lesen des Strings und zum vereinigen der Strings.

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 12:11
von NicTheQuick
Also ohne Debugger dauert bei mir beides gleich lang, nämlich immer so um die 150 ms. Eine Pointer-Version probiere ich gleich auch mal aus, wenn du magst.

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 12:11
von dysti
Ok, so ist der Test sinnlos.
Habe die Debug's durch das ersetzt:

Code: Alles auswählen

MessageRequester("Test","Zeit 2 = "+Str(ElapsedMilliseconds()-zeit)+" MilliSek."+#CRLF$+b$+#CRLF$+ LSet(b$ ,lmax,fuell$)+#CRLF$+RSet(b$ ,lmax,fuell$))
Nun ja, dann sind keine großen Unterschiede bei ausgeschalteten Debugger vorhanden.
Das mit den Pointer werde ich auch noch verstehen.
Wie würde so was aussehen?

@NicTheQuick:

Code: Alles auswählen

 Eine Pointer-Version probiere ich gleich auch mal aus, wenn du magst.
Würde mich freuen.

Was mich interessiert:
Ist eine Pointer-Version tatsächlich schneller in der Verarbeitung?

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 12:38
von NicTheQuick
Hier die halbe Pointerversion:

Code: Alles auswählen

Procedure ErsetzeString4(*input, pos.i, length.i, replacement.s)
	Protected replaceLength.i = Len(replacement)
	Protected *c.Character, *d.Character
	
	If (replaceLength <= length)
		CopyMemory(@replacement, *input + (pos - 1) * SizeOf(Character), replaceLength * SizeOf(Character))
		If (replaceLength < length)
			;MoveMemory(*input + (pos + replaceLength - 1) * SizeOf(Character), *input + (pos + length) * SizeOf(Character), )
			*c = *input + (pos + length - 1) * SizeOf(Character)
			*d = *input + (pos + replaceLength - 1) * SizeOf(Character)
			While (*c\c)
				*d\c = *c\c
				*c + SizeOf(Character)
				*d + SizeOf(Character)
			Wend
			While (*d\c)
				*d\c = 0
				*d + SizeOf(Character)
			Wend
		EndIf
	Else
		;fehlt noch
	EndIf
EndProcedure
Noch nicht eingebaut ist der Fall, dass der zu ersetzende String länger ist als der length-Parameter. Dazu müsste man den Ursprungsstring nämlich vergrößern. Ich habe damit einen Geschwindigkeitszuwachs von 33%.

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 12:51
von STARGÅTE
@dysti:

Wenn "wir" von "Pointer-Version" reden, ist damit nicht gemeint, dass man einfach ein @ vor eine Variable setzt und alles mit Memory-Befehlen umschreibt, zuminst nicht nur/nicht immer.
Es geht viel mehr darum, dass man bei einer optimierten Version alles Wissen über die Situation, das bekannt ist, einsetzt.

Dein ErsetzeString ist zwar kein gutes Beispiel, trotzdem möchte ich es daran erklären.
  • Normale Version:
    Left(String,pos-1)+ersatz+Mid(String,pos+laenge)
    Hier wird an zwei Stellen eine komplette Kopie von String gemacht, und an Left() bzw. Mid() übergeben. (uneffizient)
    Es wird zwei mal ein String erweitert: Left(String,pos-1)+ersatz und dann noch mal + Mid(String,pos+laenge)
    Auch uneffizient.
  • Verbesserte Version "mit Pointern"
    Hier würde man nicht den kompletten String übergeben sondern halt nur die Adresse (sowohl von String, als auch von ErsetzString)
    Außerdem würde man vorher genau errechnen, wie lang der neue String werden wird und dem entsprechent initiallisieren.
    Dann würde man direkt von den Adressen den Speicher kopieren, ohne ihn mit PeekS() zu lesen oder PokeS() zu schreiben.

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 12:55
von dysti
@NicTheQuick:
CopyMemory
An dieser Stelle bekomme ich die Meldung -> ungültiger Speicherzugriff. Schreibfehler an Adresse 4
Hier der Aufruf:

Code: Alles auswählen

ErsetzeString4(*a,pos,laenge,neu$)
@STARGÅTE:
Danke für die ausführliche Erklärung.
Ich habe mir das Beispiel aus dem Forum kopiert und dachte, es wäre so toll. Wie man sich irren kann.
Aber Dank euch lerne ich das Ganze noch. Ihr habt ja Geduld mit mir.

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 13:15
von NicTheQuick
Was ist denn *a? @a$?

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 13:16
von dysti
Es funktioniert, hatte versehentlich ein "*" anstatt ein "@" genommen.

Laut Ausgabe ist die Zeit: 702ms, während die anderen eine Zeit von 400/450ms haben.
Das würde bedeuten, das die NicTheQuick-Version langsamer ist!

Welche Resultate habt ihr?

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 13:28
von NicTheQuick
Hast du wieder den Debugger an? /:-> Ich habe mal die Schleifendurchläufe um das Zehnfache erhöht, weil es sonst so schnell ging.
Außerdem habe ich noch eine zweite reine Pointervariante geschrieben mit der selben Einschränkung. Der Replacement-String darf nicht größer sein als length.
Hier noch mal alles:

Code: Alles auswählen

Procedure ErsetzeString5(*input, pos.i, length.i, *replacement)
	Protected *c.Character, *d.Character
	
	*c = *input + (pos - 1) * SizeOf(Character)
	*d = *replacement
	While (*d\c And length >= 0)
		*c\c = *d\c
		*c + SizeOf(Character)
		*d + SizeOf(Character)
		length - 1
	Wend
	If (*d\c = 0)
		*d + *input + (pos + length - 1) * SizeOf(Character) - *replacement
		While (*d\c)
			*c\c = *d\c
			*c + SizeOf(Character)
			*d + SizeOf(Character)
		Wend
		While (*c\c)
			*c\c = 0
			*c + SizeOf(Character)
		Wend
	Else
		;length < len(*replacement)
	EndIf
EndProcedure

 Procedure ErsetzeString4(*input, pos.i, length.i, replacement.s)
   Protected replaceLength.i = Len(replacement)
   Protected *c.Character, *d.Character
   
   If (replaceLength <= length)
      CopyMemory(@replacement, *input + (pos - 1) * SizeOf(Character), replaceLength * SizeOf(Character))
      If (replaceLength < length)
         ;MoveMemory(*input + (pos + replaceLength - 1) * SizeOf(Character), *input + (pos + length) * SizeOf(Character), )
         *c = *input + (pos + length - 1) * SizeOf(Character)
         *d = *input + (pos + replaceLength - 1) * SizeOf(Character)
         While (*c\c)
            *d\c = *c\c
            *c + SizeOf(Character)
            *d + SizeOf(Character)
         Wend
         While (*d\c)
            *d\c = 0
            *d + SizeOf(Character)
         Wend
      EndIf
   Else
      ;fehlt noch
   EndIf
EndProcedure 

; a.s = "abcdefghijklmn"
; b.s = "xxx"
; ErsetzeString4(@a, 3, 3, @b)
; Debug a
; 
; End

Macro ErsetzeString2(String, pos, laenge, ersatz)
	Left(String, pos - 1) + ersatz + Mid(String, pos + laenge)
EndMacro
Macro ErsetzeString3(String , pos , laenge , Ersatz)
	len_original = Len(PeekS(@String)) * SizeOf(Character)
	l1 = pos + laenge - 1
	len_rest = len_original - l1
	b$ = PeekS(@String, pos - 1) + Ersatz + PeekS(@String + l1, len_rest)
EndMacro

; --------------------

time.s = ""

; Der Originalsatz
a$="Das war einmal der Satz"
Debug a$
Debug ""
; Das hier, weil ich zu faul zum selber Zaehlen bin
; und weil Änderungen ja später vom Prg. generiert werden könnten
lmax = Len(a$)
alt$ = "war einmal"
neu$ = "ist nun"
pos = FindString(a$,alt$)
laenge = Len(alt$)

; Ein Füllzeichen, wenn der Str. seine Länge behalten soll.
fuell$="."

; Nun der neue Satz 1, es ist laut Ausgabe der Schnellere
zeit = ElapsedMilliseconds()
For i=1 To 10000000
	b$=ErsetzeString2(a$,pos,laenge,neu$)
Next

time + "Zeit 2 = " + Str(ElapsedMilliseconds() - zeit) + " ms" + #CRLF$

; Nun der neue Satz 2
zeit = ElapsedMilliseconds()
For i=1 To 10000000
	ErsetzeString3(a$,pos,laenge,neu$)
Next
time + "Zeit 3 = " + Str(ElapsedMilliseconds() - zeit) + " ms" + #CRLF$

; Nun der neue Satz 3
zeit = ElapsedMilliseconds()
For i=1 To 10000000
	ErsetzeString4(@a$, pos, laenge, neu$)
Next
time + "Zeit 4 = " + Str(ElapsedMilliseconds() - zeit) + " ms" + #CRLF$

; Nun der neue Satz 4
zeit = ElapsedMilliseconds()
For i=1 To 10000000
	ErsetzeString5(@a$, pos, laenge, @neu$)
Next
time + "Zeit 5 = " + Str(ElapsedMilliseconds() - zeit) + " ms" + #CRLF$

MessageRequester("Zeiten", time)
Meine Zeiten sind:
Zeit 2 = 1585 ms
Zeit 3 = 1574 ms
Zeit 4 = 1090 ms
Zeit 5 = 811 ms