Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Format-Funktion zu langsam (https://www.delphipraxis.net/38859-format-funktion-zu-langsam.html)

Robert Marquardt 26. Jan 2005 13:10

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.

Robert_G 26. Jan 2005 13:43

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);
        }
    }
}

Jelly 26. Jan 2005 14:04

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...

negaH 27. Jan 2005 06:08

Re: Format-Funktion zu langsam
 
Delphi-Quellcode:
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;
das ist ineffizient und unleserlich.

Delphi-Quellcode:
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;
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:

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

Jelly 27. Jan 2005 08:56

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.

negaH 27. Jan 2005 15:08

Re: Format-Funktion zu langsam
 
hast du es denn schon umgebaut und getestet ?

Gruß Hagen

Jelly 27. Jan 2005 16:27

Re: Format-Funktion zu langsam
 
Zitat:

Zitat von negaH
hast du es denn schon umgebaut und getestet ?

Grad eben, und es läuft wesentlich schneller... :firejump:

Man lernt halt nie aus.

negaH 27. Jan 2005 18:04

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:
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] + '] ;' ;
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.

.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:
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;
Der Buffer wird überdimensioniert um Overhang Zeichen damit nun die neuen Funktionen für Format(), FloatToStrF() in den Buffer direkt formatieren können.

Gruß Hagen

Jelly 27. Jan 2005 20:39

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 14:03 Uhr.
Seite 2 von 2     12   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz