| Autor |
Beitrag |
walter_b
      
Beiträge: 135
Windows Vista/XP
Delphi 6
|
Verfasst: Do 17.07.08 12:25
Hallo Zusammen. Ich bin gerade mein Skript am Optimieren, da es im Moment deutlich zu langsam ist.
Lasse ich den Vorgang 1'000'000 ohne nachfolgende Textstelle durchlaufen, dauert es konstant 16ms. Entkommentiere ich nachfolgende Textstelle, so dauert es bei 1'000'000 Durchgängen ungefähr 400ms.
Es handelt sich um folgenden Teil:
Delphi-Quelltext 1: 2: 3:
| bigpass:='helloworld0000'; anf:=Copy(bigpass,0,7); ende:=Copy(bigpass,8,7); |
Um euch noch zu erläutern, was ich genau will: Bigpass wird noch dynamisch, hier wurde es für die Optimierung statisch gemacht. Jedoch behält es eine konstante länge von 14 Zeichen. Nun brauche ich jedoch die ersten sieben Zeichen in einem String und die zweiten sieben ebenfalls nochmal in einem anderen. Wie gesagt, die obengenannte funktion ist deutlich zu langsam. Gibt es ev. etwas, das mir den String genau in der Mitte halbiert? Oder gibt es eine sonstige, schneller Möglichkeit?
Vielen Dank.
|
|
Bernhard Geyer
      
Beiträge: 721
Erhaltene Danke: 3
|
Verfasst: Do 17.07.08 12:29
Stichworte wären FastMM und FastCode Project ( www.fastcodeproject.org/)
|
|
Tilman
      
Beiträge: 1405
Erhaltene Danke: 51
Win 7, Android
Turbo Delphi, Eclipse
|
Verfasst: Do 17.07.08 12:32
Hab grad kein Delphi zur Hand, allerdings könnte eine Variante nach folgendem Schema denkbar sein:
Delphi-Quelltext 1: 2: 3: 4: 5:
| type tMyStr = record case boolean of true: (str: array[1..14] of Char;); false: (pre: array[1..7] of Char; post: array[1..7] of Char;); end; |
Ich kanns grad selbst nicht testen, aber damit könnte es möglich sein direkt auf den Speicherbereich der Teilstrings zuzugreifen. Muss aber sagen dass ich mit diesen case-Anweisungen in Typen nicht wirklich auskenne.
_________________ Bringe einen Menschen zum grübeln, dann kannst du heimlich seinen Reis essen.
(Koreanisches Sprichwort)
|
|
Jerk
      
Beiträge: 251
Vista Ultimate, Ubuntu
Turbo Delphi 2006
|
Verfasst: Do 17.07.08 12:43
Vllt ist ein Grund das dein String 14 Zeichen hat, also Index von 0 bis 13 aber du bis stelle 15 kopieren willst?
|
|
nagel
      
Beiträge: 708
Win7, Ubuntu 10.10
|
Verfasst: Do 17.07.08 12:46
7 Zeichen ab Stelle 8 geht bis 14 und Strings fangen bei 1 und nicht bei 0 an.
|
|
walter_b 
      
Beiträge: 135
Windows Vista/XP
Delphi 6
|
Verfasst: Do 17.07.08 12:48
Mit FastMM wird es auf eta 320 reduziert, allerdings immernoch deutlich zu langsam.
Jerk hat folgendes geschrieben: |
Vllt ist ein Grund das dein String 14 Zeichen hat, also Index von 0 bis 13 aber du bis stelle 15 kopieren willst? |
Ich habe das ganze ursprünglich mit Copy(a,0,7) und Copy(a,7,7) gemacht und a war so definiert: "12345671234567". Als Ergebnis erhielt ich 1234567 und 7123456. Deshalb habe ich den zweiten angepasst und so funktionierte es. Von da her denke ich nicht, dass dies der Fehler ist.
Tilman hat folgendes geschrieben: |
Ich kanns grad selbst nicht testen, aber damit könnte es möglich sein direkt auf den Speicherbereich der Teilstrings zuzugreifen. Muss aber sagen dass ich mit diesen case-Anweisungen in Typen nicht wirklich auskenne.
|
Hm... Danke, werde mir das mal anschauen.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Do 17.07.08 12:50
Könntest Du etwas mehr Source posten, weil direkt aus diesem Aufruf kann man nicht viel sagen, wie das am besten zu optimieren ist.
Aber wie ich schon im andren Thread angedeutet hab:
Speicher VOR der Schleife alloziieren und dann mit direkten Speicher-Zugriffen arbeiten. Bitte dabei beachten, dass Anfang und Ende Read-Only genutzt werden müssen (sonst erzeugt Delphi Kopien davon --> Performance Drop).
Konkret kann man da aber erst was bei etwas mehr Code sagen, weil dort sich die exakte Nutzung besser erschliet.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
walter_b 
      
Beiträge: 135
Windows Vista/XP
Delphi 6
|
Verfasst: Do 17.07.08 13:03
Zur kurzen Erläuterung: Gen() geht alle Kombinationen durch (Buchstabenkombinationen, also A, AA, AB etc.). Anschliessend würde aus der aktuellen Kombination (Wort) ein 14 Zeichen langer String erstellt werden (Sorry BenBE, aber das mit dem Null-Byte habe ich noch nicht anpassen können  ). Hier habe ich das bigpass jedoch statisch gemacht. Danach sollte das ganze mit parityshift noch ein wenig hässlich gemacht werden und mit DecodeText (wurde hier weggelassen) verschlüsselt und nachher zusammengesetzt. Falls ihr sonst noch irgendwo eine Optimierungsmöglichkeit seht, wäre ich euch sehr dankbar
Edith: Wegen der angedeuteten Optimierung von dir, BenBE: Da ich mich nicht so wirklich mit PChar auskenne, weiss ich nicht recht, wie ich das anwenden soll. 
Zuletzt bearbeitet von walter_b am Mo 04.08.08 14:47, insgesamt 1-mal bearbeitet
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Do 17.07.08 13:11
Ändert doch aber nichts am der Performancebremse. Das es sich hier um konstante Längen handelt, dürfte man mit einigen Kopier- und Castingoperationen weiter kommen. So gehts ein wenig schneller:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| Var bigpass,anf,ende : String;
Type P4 = ^Integer; P2 = ^Word; P1 = ^Byte;
Var p : Integer;
begin SetLength (anf,7); setLength (ende,7); p := integer (@bigpass[1]); P4(@anf[1])^ := P4(p)^; P2(@anf[5])^ := P2(p+4)^; P1(@anf[7])^ := P1(p+6)^; P4(@ende[1])^ := P4(p+7)^; P2(@ende[5])^ := P2(p+12)^; P1(@ende[7])^ := P1(p+13)^; End; |
_________________ Na denn, dann. Bis dann, denn.
|
|
walter_b 
      
Beiträge: 135
Windows Vista/XP
Delphi 6
|
Verfasst: Do 17.07.08 13:19
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Do 17.07.08 13:26
Na anf[1] ist das erste Zeichen des Strings 'anf' und '@' die Adresse davon. P4(@anf[1]) sagt Delphi, das an dieser Stelle ein Integer steht und P4(@anf[1])^ liefert diesen Integer. Geht aber noch schneller:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| Type T7 = array[0..7] Of Byte; P7 = ^T7;
Var p : Integer; begin SetLength (anf,7); setLength (ende,7); p := integer (@bigpass[1]); P7(@anf[1])^ := P7(p)^; P7(@ende[1])^ := P7(p+7)^; End; |
_________________ Na denn, dann. Bis dann, denn.
|
|
walter_b 
      
Beiträge: 135
Windows Vista/XP
Delphi 6
|
Verfasst: Do 17.07.08 13:34
Aah, das ist demfall bloss für die Definition von anf und ende, oder? Womit würde ich nachher weiterarbeiten? P7? Oder wird nachher einfach der String normal in anf und ende gespeichert? 
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Do 17.07.08 13:35
Ausprobieren (die Strings sind natürlich korrekt befüllt).
_________________ Na denn, dann. Bis dann, denn.
|
|
Allesquarks
      
Beiträge: 510
Win XP Prof
Delphi 7 E
|
Verfasst: Do 17.07.08 13:40
PChar ist einfach wie der Name schon sagt ein Zeiger auf Buchstaben also ziemlich ähnlich zum array of byte. Insbesondere verzichtet es auf vieles von dem Delphi-String Schnickschnack. Je nach deiner Programmierung kann man Strings üblicherweise extrem optimieren. Delphi ruft bsp. bei jeder Benutzung von strings intern die Funktion uniquestring auf, die sicherstellt, dass man nicht andere Variablen (da strings eigentlich auch nur Zeiger sind) ändert. Wenn du darauf achtest dann kannst du dir diesen Overhead durch pchar schoneinmal sparen. Ich schätze auch mal, dass der dumme Compiler wegen deiner 14 #0 auch vierzehnmal die Stringverkettung aufruft. Ich nehme an, du willst damit garantieren, dass der string auch 14 Zeichen lang ist. Doch in diesem Fall wäre der kürzeste Code (deiner) nicht der eleganteste. In deinem Fall würde ich einfach eine Abfrage einbauen, ob der überhaupt so lang ist. Das wäre wesentlich schneller. Falls es wirklich nur darum geht, dass der mindestens 14 Zeichen lang ist würde auch ein simples setlength reichen. Das wäre zumindest noch schneller als die derzeitige Version schätze ich.
Speziell copy kann man bei strings auch komplett vermeiden, indem man sich über einen Zeiger und eine Länge einfach merkt, wo man in einem globalen String arbeiten möchte.
P.S.:mit dem @ bekommt man die Adresse der Variablen, an die man mit ^ (dereferenzieren) dann schreiben kann.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Do 17.07.08 13:47
Wenn es hier wirklich darum geht, mit konstanter Länge zu arbeiten, würde ich keine Strings umherschubsen, sondern Array of Char entsprechend dimensionieren und daraus ableiten. String sollte in dem Kontext wirklich nur dort verwendet werden, wo solch ein Puffer als Zeichenfolge dargestellt werden muss; ansonsten mit direktn Speicherzugriffen arbeiten, wie oben gezeigt.
Interessant könnte in dem Zusammenhang auch die Funktion StrPas sein 
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
walter_b 
      
Beiträge: 135
Windows Vista/XP
Delphi 6
|
Verfasst: Do 17.07.08 13:56
@all: Vielen Dank für eure Geduld und Hilfe  Habe zuvor noch nie mit PChar gearbeteitet, aber werde das ganze jetzt mal bisschen genauer anschauen und mich ins Thema einarbeiten versuchen. Mal schauen, ob es was bringt. 
|
|
walter_b 
      
Beiträge: 135
Windows Vista/XP
Delphi 6
|
Verfasst: Do 17.07.08 14:30
Was genau macht die Integerfunktion hier:
Delphi-Quelltext 1:
| p := integer (@bigpass[1]); |
Habe anf, ende und p auslesen lassen. anf und ende passen wunderbar  Hingegen für p kommt was seltsames raus. Habe die Funktion nirgends in der Hilfe gefunden.
Und ausserdem verstehe ich nicht wirklich, wofür T7 deklariert wird, da es ja nicht verwendet wird.
|
|
Hidden
      
Beiträge: 2242
Erhaltene Danke: 55
Win10
VS Code, Delphi 2010 Prof.
|
Verfasst: Do 17.07.08 14:57
Delphi-Quelltext 1:
| p := integer (@bigpass[1]); |
p ist ein Zeiger. Dass der einen komischen Inhalt hat, braucht dich nicht zu wundern, du musst ihn dereferenzieren, so ist es nur eine Adresse.
Integer ist ein TypeCast und keine funktion: Es wird so behandelt, als stände an dieser Position ein Integer. Dieser ist 4 Byte lang und umdfasst somit die ersten vier Zeichen nach bigpass[1].
mfG,
_________________ Centaur spears can block many spells, but no one tries to block if they see that the spell is a certain shade of green. For this purpose it is useful to know some green stunning hexes. (HPMoR)
|
|
Tilman
      
Beiträge: 1405
Erhaltene Danke: 51
Win 7, Android
Turbo Delphi, Eclipse
|
Verfasst: Do 17.07.08 15:21
So, habs mal kurz ausprobiert:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| type tMyStr = record case boolean of true: (str: array[1..14] of Char;); false: (anfang: array[1..7] of Char; ende: array[1..7] of Char;); end;
var a: tMyStr; [..] a.str :='helloworld0000'; |
Funzt relativ schnell. Allerdings kann ich dir nicht sagen wie man a.str einen String zuweisen kann; mit Konstanten Literalen klappts zwar, aber irgendwie sollte man ja auch einen string casten können 
_________________ Bringe einen Menschen zum grübeln, dann kannst du heimlich seinen Reis essen.
(Koreanisches Sprichwort)
|
|
walter_b 
      
Beiträge: 135
Windows Vista/XP
Delphi 6
|
Verfasst: Do 17.07.08 15:29
Habe gerade ein Problem. Die aktuelle Kombination steckt ja in "Wort". Wie bringe ich jetzt den Wert davon in den Array of Char bigpass? Steht: Incompatible types: Array and String.
|
|