![]() |
Format-Funktion zu langsam
Für eine simulation muss ich eine 200x200x200=800.000 Werte in einer Textfile speichern. Dazu ruf ich 800.000 mal die Format-Funktion auf:
Delphi-Quellcode:
Das dauert aber ELEND lange... Gibts da nicht eine Methode, die da wesentlich schneller arbeitet... FloatToStr bringt mir auch nix.
format('%.4f ',[C[Nr]]) ;
|
Re: Format-Funktion zu langsam
Hi,
evtl. ist Str() schneller..? Gruß Stephan :dance: |
Re: Format-Funktion zu langsam
Zitat:
Unabhängig davon, sind ca. 13 Sekunden für 8Mio Werte wirklich zu viel?
Delphi-Quellcode:
...:cat:...
procedure TForm1.Button1Click(Sender: TObject);
var Start, Stop, Freq: Int64; I: Integer; Id: Double; begin QueryPerformanceCounter(Start); for I := 1 to 8000000 do begin Id := I; Format('%.4f', [Id]); end; QueryPerformanceCounter(Stop); QueryPerformanceFrequency(Freq); Label1.Caption := Format('%f ms', [(Stop - Start) * 1000 / Freq]); end; |
Re: Format-Funktion zu langsam
Zitat:
Daneben gibt es noch: FloatToStrF und FloatToDecimal & FloatToText |
Re: Format-Funktion zu langsam
Zitat:
Zitat:
|
Re: Format-Funktion zu langsam
Zeig mal den Code drumherum.
|
Re: Format-Funktion zu langsam
Zitat:
Delphi-Quellcode:
Variante 1 : 5.671 ms
procedure TForm1.Button1Click(Sender: TObject);
var Start, Stop, Freq: Int64; ndx : Integer; sl : TStringList; Id: Double; begin QueryPerformanceCounter(Start); sl := TStringList.Create; try for ndx := 1 to 8000000 do begin Id := ndx; // sl.Add (FloatToStr (id)); // Variante 1 // sl.Add(Format('%.4f', [Id])); // Variante 2 sl.Add(FormatFloat('########.0000',ID)); // Variante 3 end; QueryPerformanceCounter(Stop); QueryPerformanceFrequency(Freq); Label1.Caption := Format('%f ms', [(Stop - Start) * 1000 / Freq]); sl.SaveToFile('c:\liste3.txt'); finally sl.Free; end; end; Variante 2 : 7.143 ms Varinate 3 : 7.657 ms |
Re: Format-Funktion zu langsam
Zitat:
Delphi-Quellcode:
Die Add Methode... FS ist ein TFileStream:
{ 3D-Matrix mit Parametern }
for Nr := 1 to 2 do begin for iz := 0 to G.z-1 do begin V_line[Nr] := format('%s (:,:,%d) = [',[A[Nr],iz+1]) ; for ix := 0 to G.x-1 do begin for iy := 0 to G.y-1 do with Thread.Cells[ix,iy,iz] do begin V_line[Nr] := V_line[Nr] + FloatToStrF (C[Nr],ffFixed,7,4) + ' ' ; // langsam, heisst ung. 20 min. //V_line[Nr] := V_line[Nr] + '0.0001 ' ; // schnell, par Sekündchen if (iy = G.y-1) and (ix < G.x-1) then begin V_line[Nr] := V_line[Nr] + '; ' ; end ; end ; end ; V_line[Nr] := V_line[Nr] + '] ;' ; Add (V_line[Nr]) ; V_line[Nr] := '' ; end ; Add ('') ; end ;
Delphi-Quellcode:
An der Add Methode kanns aber meiner Ansicht nach nicht liegen, da die ja auch aufgerufen wird, wenn ich Format weglasse, und direkt einen Wert schreibe.
procedure TMCBasisExport.Add(AText: string);
var buf : string ; begin if FS <> nil then begin buf := AText+#13#10 ; FS.Write(buf[1],length(buf)) ; end else begin raise exception.Create('Datei kann nich beschrieben werden.'); end ;end; |
Re: Format-Funktion zu langsam
[quote="Jelly"]
Delphi-Quellcode:
Deine Auskommentierung ist nicht fair, da du den Zugriff auf das Array C[] nicht berücksichtigt:
{ 3D-Matrix mit Parametern }
for Nr := 1 to 2 do begin for iz := 0 to G.z-1 do begin V_line[Nr] := format('%s (:,:,%d) = [',[A[Nr],iz+1]) ; for ix := 0 to G.x-1 do begin for iy := 0 to G.y-1 do with Thread.Cells[ix,iy,iz] do begin V_line[Nr] := V_line[Nr] + FloatToStrF (C[Nr],ffFixed,7,4) + ' ' ; // langsam, heisst ung. 20 min. //V_line[Nr] := V_line[Nr] + '0.0001 ' ; // schnell, par Sekündchen
Delphi-Quellcode:
// Variante 1
V_line[Nr] := V_line[Nr] + FloatToStrF (C[Nr],ffFixed,7,4) + ' ' ; // Variante 2 (ohne FloatToStrF) dummy_float := C[Nr]; // optimierung des compilers ausschalten, sonst wird wegoptimiert // und da da Array C[] wohl zu Thread.cells gehört, wird dies wohl die Hauptursache // für dein Performanceproblem sein !!! V_line[Nr] := V_line[Nr] + '0.0001 ' ; |
Re: Format-Funktion zu langsam
@shmia: hättest du Recht haben können... Habs aber grad getestet, und das ändert aber nichts am Verlauf :gruebel:
|
Re: Format-Funktion zu langsam
Array-Properties koenne erschreckend langsam sein.
Ich habe ein Programm 10x schneller bekommen indem ich die booleschen Werte nicht dauernd aus der Checked-Property eines Listviews gelesen habe. Einmal in ein array von Booleans kopiert und alles war gut eh schnell. |
Re: Format-Funktion zu langsam
Ich habe es eben mal aus Jux (und aufgrund der Mittagspause :zwinker: ) in .Ne probiert.
Fazit: Es ist langsamer, aber es ist auch alles andere als hübsch oder optimiert. :P Ich komme auf create array: 0.3967 ms fill 8,000,000 random values: 427.5188 ms conversion: 8054.1218 ms write to disk: 13924.7499 ms overall time: 22457.428 ms Press any key to continue
Code:
using System;
using System.Collections; using System.IO; using RobertG.Invoked.ProcessInfo; namespace DelphiPRAXIS.Jelly.Save3dArray { internal class Program { /// <summary> /// Entry point /// </summary> /// <param name="args">Argumente (Nummer eins ist das zu schreibende Dateichen)</param> [STAThread] static void Main(string[] args) { Program program = new Program(); program.Run(args[0]); } PerformanceCounter counter; double[,,] values; public Program() { counter = new PerformanceCounter(); } void Run(string fileName) { PerformanceCounter overallCounter = new PerformanceCounter(); overallCounter.Start(); values = CreateArray(); int valueCount = (int)values.LongLength; FillRandomNumbers(valueCount); ArrayList lines = new ArrayList(valueCount); ConvertNumbers(lines); SaveToFile(fileName, lines); overallCounter.Stop(); Console.WriteLine("overall time: {0:0.####} ms", overallCounter.Duration); } double[,,] CreateArray() { counter.Start(); double[,,] values = Array.CreateInstance(typeof (double), new int[3] {200, 200, 200}) as double[,,]; counter.Stop(); Console.WriteLine("create array: {0:0.####} ms", counter.Duration); return values; } void FillRandomNumbers( int valueCount) { counter.Start(); Random random = new Random(valueCount); for (int i = 0; i < values.GetLength(0); i++) { for (int j = 0; j < values.GetLength(1); j++) { for (int k = 0; k < values.GetLength(2); k++) { values[i, j, k] = random.NextDouble(); } } } counter.Stop(); Console.WriteLine("fill {0:0,0} random values: {1:0.####} ms", values.LongLength, counter.Duration); } void ConvertNumbers(ArrayList lines) { counter.Start(); foreach (double value in values) { lines.Add(value.ToString("0.####")); } counter.Stop(); Console.WriteLine("conversion: {0:0.####} ms", counter.Duration); } void SaveToFile(string fileName, IList lines) { FileStream stream = null; counter.Start(); if (File.Exists(fileName)) { stream = new FileStream(fileName, FileMode.Truncate, FileAccess.Write); } else { stream = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write); } BinaryWriter writer = new BinaryWriter(stream); foreach (string line in lines) { writer.Write(line); } stream.Close(); counter.Stop(); Console.WriteLine("write to disk: {0:0.####} ms", counter.Duration); } } } |
Re: Format-Funktion zu langsam
Ich glaube in meinem Fall hängt es wirklich an der Format oder FormatFloat Funktion... Das Schreiben der Daten klappt recht schnell. Sobald irgendwo ein Aufruf mit Format o.ä. drin steht, dauerts Minuten...
|
Re: Format-Funktion zu langsam
Delphi-Quellcode:
das ist ineffizient und unleserlich.
procedure TMCBasisExport.Add(AText: string);
var buf : string ; begin if FS <> nil then begin buf := AText+#13#10 ; FS.Write(buf[1],length(buf)) ; end else begin raise exception.Create('Datei kann nich beschrieben werden.'); end ; end;
Delphi-Quellcode:
Die Contentation in deinem Source mit Buf := AText + #13#10 führt minimal vier langwierige und unnötige Operationen aus, die du so nicht siehst:
procedure TMCBasisExport.Add(const AText: String);
const CR: PChar = #13#10; begin if FS = nil then raise exception.Create('Kein Dateistream erzeugt.'); FS.Write(PChar(AText)^, Length(AText)); FS.Write(CR^, 2); end; 1.) Buf = AText -> setze @Buf^ = @AText^, interner AText.RefCounter +1 erhöhen 2.) Buf = Buf + #13#10 2.1.) alloziere neuen Speicher mit Length(AText) + 4 2.2.) kopiere Inhalt von AText == Buf nach neuen Speicher 2.3.) AText.RefCounter -1 2.4.) setze Buf auf neuen Speicher 2.5.) falls (Length(ABuf) + 4) mod 16 < 2 dann 2.5.1.) alloziere neuen Speicher mit Length(Buf) + 2 um #13#10 hinzufügen zu können 2.5.2.) kopiere nun Buf nach neuen Speicher 2.5.3.) dealloziere alten Speicher im Buf 2.5.4.) setze Buf auf neuen Speicher 2.6.) setze Länge vom String Buf auf ++2 2.7.) kopiere #13#10 ans Ende von Buf 2.8.) Buf.RefCounter -1 2.9.) Speicher in Buf freigeben All das passiert bei Buf := AText + #13#10; In meinem Beispiel passiert dagegen folgendes: 0.) nichts, kein unnötiges Stringhandling Gruß Hagen |
Re: Format-Funktion zu langsam
@Hagen:
dein Code mag ja effetkiver sein, da stimm ich dir zu. Werd das mal umbauen... Nur wird meine funktion dadurch nicht viel schneller, da alle Zeit in der Format-Funktion verbraten wird... Aber da schein ich nix dran ändern zu können. Muss ich halt warten. |
Re: Format-Funktion zu langsam
hast du es denn schon umgebaut und getestet ?
Gruß Hagen |
Re: Format-Funktion zu langsam
Zitat:
Man lernt halt nie aus. |
Re: Format-Funktion zu langsam
Gut, du hast also gelernt das die Contenation von LongStrings sehr langsam sind und das es eventuell besser sein kann erstmal einfach die Tipps der erfahrenen Programmierer nicht sofort anzuzweifeln :)
In deinem Source betrifft das 6 Stellen:
Delphi-Quellcode:
Statt also mit V_line[nr] zu arbeiten änderst du sie in Aufrufe von Add() um. Im .Add() nimmst du das #13#10 raus und baust es manuell in deine Schleife rein.
V_line[Nr] := format('%s (:,:,%d) = [',[A[Nr],iz+1]) ;
V_line[Nr] := V_line[Nr] + FloatToStrF (C[Nr],ffFixed,7,4) + ' ' ; // langsam, heisst ung. 20 min. //V_line[Nr] := V_line[Nr] + '0.0001 ' ; // schnell, par Sekündchen if (iy = G.y-1) and (ix < G.x-1) then begin V_line[Nr] := V_line[Nr] + '; ' ; end ; end ; end ; V_line[Nr] := V_line[Nr] + '] ;' ; .Add() selber kann nun zusätzlich beschleunigt werden indem man einen zb. 4Kb großen Buffer benutzt. Das beschleunigt dann das Dateisystem des Betriebsystemes das mit 1Kb-4Kb großen Schreibzugriffen am effizientesten ist. Als nächstes würde man die Format() und FloatToStrF() funktionen umbauen. Diese würde dann NICHT mehr einen LongString als Resultat zurückgeben sondern in diesem großen Buffer[] direkt hinein-formatieren. Somit wären alle LongString's und deren ständige Speicher- Alloziereungen/Deallozioerungen/Kopierungen entfernt. Deine Funktion könnte abstrahiert dann so aussensehen:
Delphi-Quellcode:
Der Buffer wird überdimensioniert um Overhang Zeichen damit nun die neuen Funktionen für Format(), FloatToStrF() in den Buffer direkt formatieren können.
procedure ExportMatrix(const Filename: String, ... blabla);
const Overhang = 256; var Buffer: array[0..1024 * 4 -1 + Overhang] of Char; // 256 zeichen mehr für inplaced Format() etc. funktionen BufPos: Integer; Stream: TStream; procedure WriteBuffer; begin Stream.Write(Buffer, BufPos); BufPos := 0; end; procedure Put(Text: Char); overload; begin Buffer[BufPos] := Text; Inc(BufPos); if BufPos >= SizeOf(Buffer) - Overhang then WriteBuffer; end; procedure Put(const Text: PChar); overload; begin with Text^ <> #0 do begin Put(Text^); Inc(Text); end; end; procedure DoExport; var I,J: Integer; ..,blabla begin // hier Matrix exportieren for I := 0 to do for J := 0 to do begin Put(...); for K := 0 to do begin Put(...); Put(' '); end; Put(#13#10); end; end; begin BufPos := 0; Stream := TFileStream.Create(FileName, fmCreate); try DoExport; WriteBuffer; // Rest des Buffers speichern finally Stream.Free; end; end; Gruß Hagen |
Re: Format-Funktion zu langsam
Zu meiner Schande muß ich gestehen, daß ich noch nie so tief Zeit in die Performance von Algos reingesteckt habe. :oops:
Ich nehm mir deinen Rat zu Herzen und werds einbauen, rsp mich zumindest mehr mit so Problemen allg. beschäftigen. Aber unter Zeitdruck klappt das nun mal leider nicht immer ;-) Danke für den Tip... :zwinker: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:06 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz