Vergleich der Schnelligkeit normale und Pointer-Version

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
dysti
Beiträge: 656
Registriert: 10.02.2006 18:34
Wohnort: Schlicktown

Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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 ""
PB5 / Spiderbasic / WB14 / Win7 / Win8.1 / Win10 / Debian 9
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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.
Benutzeravatar
dysti
Beiträge: 656
Registriert: 10.02.2006 18:34
Wohnort: Schlicktown

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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?
Zuletzt geändert von dysti am 06.02.2013 12:39, insgesamt 1-mal geändert.
PB5 / Spiderbasic / WB14 / Win7 / Win8.1 / Win10 / Debian 9
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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%.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
dysti
Beiträge: 656
Registriert: 10.02.2006 18:34
Wohnort: Schlicktown

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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.
PB5 / Spiderbasic / WB14 / Win7 / Win8.1 / Win10 / Debian 9
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag von NicTheQuick »

Was ist denn *a? @a$?
Benutzeravatar
dysti
Beiträge: 656
Registriert: 10.02.2006 18:34
Wohnort: Schlicktown

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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?
PB5 / Spiderbasic / WB14 / Win7 / Win8.1 / Win10 / Debian 9
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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
Antworten