Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi FOR oder WIHLE was ist schneller (Stringgrid befüllen) (https://www.delphipraxis.net/129241-oder-wihle-ist-schneller-stringgrid-befuellen.html)

Stef_One 15. Feb 2009 11:13


FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Hallo zusammen,

kann mir jemand von euch sagen was schneller ist FOR oder WHILE Schleifen ich bin gerade dabei mein Programm zu optimieren.
Dabei werden mehrere Schleifen durchlaufen und die aufbereiteten Ergebnisse dann in einem Sringgrid dargestellt. Momentan stoße ich dabei auf Performance Probleme, ich habe auch schon probiert eine BeginUpdate/EndUpdate einzubauen allerdings scheint das mit einem Stringgrid nicht so einfach zu funktionieren wie mit einer Treeview oder Listbox-Komponente alternativ dazu setzte ich den RowCount des Stringgrid jetzt erst zum Schluss nach der For-Schleife auf den richtigen Wert.

mkinzler 15. Feb 2009 11:21

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
For ist m.W als While-Schleife implementiert. es sollte dann eigentlich keinen Unterschied zwischen den beiden Varianten geben

jfheins 15. Feb 2009 11:21

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Wenn du bereits vorher weist, wie oft die Schleife ausgeführt werden muss, ist die for-Schleife besser.

Wobei das im Endeffekt egal sein dürfe da iirc die for-Schleife intern in eine While-Schleife umgewandelt wird. Aber evtl. kann der Compiler dadurch noch etwas optimieren da die Zählervariable nicht verändert werden kann ...

Aber wenn dich der Geschwindigkeitsunterschied interessiert, optimierst du wahrscheinlich an der falschen Stelle :gruebel:

Um das Halbwissen perfekt zu machen:

Delphi-Quellcode:
for i := 0 to 5 do
begin
// ...
end;
wird zu
Delphi-Quellcode:
i := 5;
while(i <> 0)
begin
// ...
dec(i);
end;

Te7Ris 15. Feb 2009 11:28

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Hallo,

überleg erstmal ob du dir nicht die ein oder andere verschachtelte Schleife komplett sparen
kannst, da hier der größte "Zeitverschleiß" auftritt...

ansonsten kannste noch probieren, die Ergebnisse erst in ein Array zwischenzuspeichern und dann
nach dem durchlaufen der Schleifen auszugeben... da das "auf den Bildschirm schreiben" länger
dauert als man vermuten würde...


Gruß Maxi

Stef_One 15. Feb 2009 11:33

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
@Te7Ris: ja dem Problem wollte ich schon aus dem Weg gehen indem ich den Row Count des Stinggrid erst nach der Schleife setze, allerdings bringt das kein Effekt, nach unnötige Verschachtelungen hab ich auch bereits gesucht allerdings ist da jetzt nicht mehr alt soviel rauszuholen.

alzaimar 15. Feb 2009 12:01

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Da das Befüllen eines Stringgrids ca. 10.00.000x mehr Performance verbrät als ein eventuell vorhandener Unterschied zwischen FOR- und WHILE-Schleife kannst Du dich getrost auf andere Sachen konzentrieren.

Z.B. das allseits beliebte: "Trenne Funktion und Darstellung". Verwende also kein Stringgrid, um 100-Tausende von Daten im Speicher zu halten. Da wird sowieso niemals jemand durchscrollen. Verwende ein Grid nur zur Darstellung eines Ausschnittes deiner Tabelle, so wie z.B. das TDBGrid, das einen kleinen Ausschnitt aus einer beliebig großen Datenmenge (TDataset) zeigt.

Stef_One 15. Feb 2009 12:12

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
@alzaimar: ja das ist bereits schon so, alle daten die ich brache sind in records gespeichert, im stringgrid werden sie nur aufbereitet angezeigt!

Hansa 15. Feb 2009 12:23

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Das liegt ja nur an der Anzeige. Die ist grottenlahm. Mache das mal so :

Sg.hide;
Füllen
Sg.show;

alzaimar 15. Feb 2009 12:54

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Zeig mal ein wenig Code. Wie gesagt, ich vermute, Du hast einfach zu viele Records. Hier wäre der Einsatz eines TDatasets und TDBGrid wohl angebracht. Alternativ könntest Du eine TListView im OwnerData-Modus laufen oder nimmst gleich ein TVirtualTreeView, das dafür besonders geeignet ist.

Stef_One 15. Feb 2009 13:22

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Also das ganze ist ein Tool für meinen Arbeitgeber zur Planung von Schichtplänen, leider ist die Sache schon soweit fotgeschritten das es jetzt nicht so einfach ist hier ein paar Codefetzen hinzuwerfen

Also das Stringgrid ist so aufgebaut



Kostenstelle Arbeitsplatzgruppe Name Personnummer Schicht 1.1 2.1 3.1 4.1 .....das ganze für 4 Wcohen



im Testmodus sind 45 Mitarbeiter eingepflegt
der Record dafür sieht so aus

Delphi-Quellcode:
type
    TData = record
     Name              : String[20];
     Vorname           : String[15];
     Personalnummer    : String[15];
     Kostenstelle      : String[15];
     Arbeitsplatzgruppe : String[16];
     Ersthelfer        : Boolean;
     Vorarbeiter       : Boolean;
     Leiharbeiter      : Boolean;
     Username          : String[20];
     Telefonnummer     : String[20];
     Meister           : Boolean;
     Schicht           : String[60];
     StartSchicht      : String[2];
     Start_Date        : String[20];
     ErlaubteKST       : String[255];
     EinsatzMoeglichkeit : String[255];
end;
dann get es weiter mit einen "Übersteuern" Record
wird benötigt um Änderungen im Schitplan anzuzeigen
und nicht die eigentlichen Schicht abändern zu müssen
so das der einzelne Mitarbeiter immer im gleichen Rhythmus bleibt

Delphi-Quellcode:
type
    TChangeData = record
     SchichtTyp        : String[5];
     Datum             : TDateTime;
     Personalnummer    : String[15];
     Kostenstelle      : String[15];
     Arbeitsplatzgruppe : String[15];
     Wochenweise       : Boolean;
end;

type
    TUebersteuern = record
       Daten : Array [1..100000] of TChangeData;
       Count :integer;
end;

die function um die schichten zu berechnen sieht so aus

Delphi-Quellcode:
function GetSchicht(Mitarbeiter:TData;KW:Integer;Year:Integer;Datum:TDateTime;Weekly:Boolean):String;
var
      SchichtSystem    :String;
      EinzelSchicht    :String;
      EinzelSchichtTag :String;
      i,x              :integer;
     // savepos          :integer;
      SchichtList      :TStringList;
      ErrechnetesDatum :TDateTime;
      EndDatum         :TDateTime;
      Tagessumme       :Integer;
      y                :Integer;
      //5tagesansicht übersteuert in wochenansicht
      q                :Integer;
      SaveDate         :Tdatetime;
      SaveSchicht      :String;
      tagecounter      :Integer;
begin

      if mitarbeiter.Schicht='' then exit;

      SchichtList:= TStringList.Create;
      //+++++++Schichtsystem des Mitarbeiters suchen++++++++++
      for i:=1 to Settings.SchichtenCount do
       begin
        if Mitarbeiter.Schicht=settings.Schichten[i].Name then
           begin
              SchichtSystem:=settings.Schichten[i].Reihenfolge;
              break;
           end;
       end;

      //+++++++Schichtsystem auseinander flücken
        for i:=1 to Length(SchichtSystem) do
        begin
          if SchichtSystem[i]<>';' then
            begin
               EinzelSchicht:=EinzelSchicht+SchichtSystem[i];
            end else
            begin
              SchichtList.Add(EinzelSchicht);
              //main_window.ListBox1.Items.Add(EinzelSchicht) ;
              EinzelSchicht:='';
            end;
        end;

      //Anfangschichtsystem finden mit x vergleichen gegen hinterlegten string
      x:=StrtoInt(Mitarbeiter.StartSchicht)-1;

        //################################## Ansicht Tageweise/Wochenweise #################################
        //################################## Ansicht Tageweise/Wochenweise #################################

        //Tage pro schicht ermitteln und ab startdatum rechnen
        Tagessumme:=0;
        ErrechnetesDatum:=0;
        if Weekly=true then Datum:=StartOfAWeek(Year, KW, 1);    //noch end datum eintragen errechtet aus der kw

        while ErrechnetesDatum <= Datum do
          begin
              EinzelSchichtTag:=SchichtList.Strings[x];

              EinzelSchichtTag:=StringReplace(EinzelSchichtTag,'N','', [rfReplaceAll]);
              EinzelSchichtTag:=StringReplace(EinzelSchichtTag,'S','', [rfReplaceAll]);
              EinzelSchichtTag:=StringReplace(EinzelSchichtTag,'F','', [rfReplaceAll]);
              EinzelSchichtTag:=StringReplace(EinzelSchichtTag,'W','', [rfReplaceAll]);

              Tagessumme:=Tagessumme+StrToInt(EinzelSchichtTag);
              ErrechnetesDatum:=StrToDate(Mitarbeiter.Start_Date)+Tagessumme;


              if pos('F',SchichtList.Strings[x])>0 then result:='F';//'Frühschicht';
              if pos('S',SchichtList.Strings[x])>0 then result:='S';//'Spätschicht';
              if pos('N',SchichtList.Strings[x])>0 then result:='N';//'Nachtschicht';
              if pos('W',SchichtList.Strings[x])>0 then result:='.';//'Wochenende';

              inc(x);
              if x> SchichtList.Count-1 then x:=0;
         end;
         //++++++++++++++++++++++++++++Wochenende setzten++++++++++++++++++++++++++++++
         if Weekly=false then if DayOfTheWeek(Datum)>5 then result:='.';   /////
         //++++++++++++++++++++++++++++Wochenende setzten++++++++++++++++++++++++++++++

         

              //##############################Übersteuern Start#################################
              //################################################################################
              for y:=1 to Uebersteuern.Count do
                  begin
                     if Uebersteuern.Daten[y].Personalnummer=Mitarbeiter.Personalnummer then
                        begin

                          if Uebersteuern.Daten[y].Wochenweise=true then
                              begin

                                   if weekly=true then  //ansicht in KW
                                     begin
                                       if (Uebersteuern.Daten[y].Datum=StartOfAWeek(Year, KW, 1)) then result:=Uebersteuern.Daten[y].SchichtTyp;
                                     end else
                                     begin               //ansicht Tageweise buchung alle 5 arbeitstage!
                                       if (Uebersteuern.Daten[y].Datum<=Datum) and (Uebersteuern.Daten[y].Datum+4>=Datum) then
                                          result:=Uebersteuern.Daten[y].SchichtTyp;
                                     end;

                               end else
                               begin
                                     //tagesansicht
                                     if weekly=false then
                                      begin
                                        if Uebersteuern.Daten[y].Datum=Datum then result:=Uebersteuern.Daten[y].SchichtTyp;
                                      end else
                                      begin
                                      //wochenasicht gucken ob 5 gleiche einträge vorhanden sind
                                        if Uebersteuern.Daten[y].Datum=Datum then
                                          begin
                                             SaveDate:=StartOfTheWeek(Uebersteuern.Daten[y].Datum);
                                             SaveSchicht:=Uebersteuern.Daten[y].SchichtTyp;
                                             tagecounter:=0;
                                             q:=1;

                                          //nochmal die daten durchsuchen für einträge in gleicher woche mit gleicher schicht
                                          while q<=Uebersteuern.Count do
                                            begin
                                               if (Uebersteuern.Daten[q].Personalnummer=Mitarbeiter.Personalnummer) then
                                               begin
                                                 if (Uebersteuern.Daten[q].Datum=SaveDate+tagecounter) and
                                                  (Uebersteuern.Daten[q].SchichtTyp=SaveSchicht) then
                                                    begin
                                                        inc(tagecounter);
                                                        q:=0;
                                                        if tagecounter>4 then break;
                                                    end
                                                end;

                                               inc(q)
                                            end;
                                             if tagecounter>4 then result:=SaveSchicht;
                                          end;

                                      end;
                               end;
                           end;

                    end;

              //##############################Übersteuern Ende##################################


             //sollte der Starttermin vor dem aktuellen datum liegen in der vergangenheit
             if weekly=true then if StartOfAWeek(Year, KW, 1) <StrToDate(Mitarbeiter.Start_Date) then result:='xxx';
             if weekly=false then if Datum <StrToDate(Mitarbeiter.Start_Date) then result:='xxx';

        SchichtList.Free;
end;

thkerkmann 15. Feb 2009 15:18

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Hi,

also wenn Du schon beim Optimieren bist:

Delphi-Quellcode:
   if pos('F',SchichtList.Strings[x])>0 then result:='F';//'Frühschicht';
   if pos('S',SchichtList.Strings[x])>0 then result:='S';//'Spätschicht';
   if pos('N',SchichtList.Strings[x])>0 then result:='N';//'Nachtschicht';
   if pos('W',SchichtList.Strings[x])>0 then result:='.';//'Wochenende';
Hier wird 4 x ein String aus der Liste geholt um einen Vergleich durchzuführen.
Wenn aber einer der Vergleiche ok geht, wird auch noch weiter verglichen.

Also besser
Delphi-Quellcode:
  schList := SchichtList.Strings[x];
  if pos('F',schList)>0 then
    result:='F'  //'Frühschicht'
  else if pos('S',schList)>0 then
    result:='S' //'Spätschicht'
  else if pos('N',schList)>0 then
    result:='N'  //'Nachtschicht'
  else if pos('W',SchichtList.Strings[x])>0 then
    result:='.'; //'Wochenende'
Wenn es gewünscht ist, dass z.B Wochenende den Vorrang hat (theoretisch könnten ja alle Buchstaben in schList auftauchen,
dann musst du einfach die Reihnenfolge der Prüfungen entsprechend dem Vorrang tauschen.

Gruss

himitsu 15. Feb 2009 15:22

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Und was ist eigentlich, wenn mal weder F, S, N oder W in SchichtList.Strings[x] vorkommt?

HaJo 15. Feb 2009 16:10

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Tja, was ich hier lese riecht für mich eher nach einer klassischen Datenbank-Aufgabe, statt das ganze im Memory abzuarbeiten.

Chemiker 15. Feb 2009 16:26

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Hallo Stef_One,

Delphi-Quellcode:
Daten : Array [1..100000] of TChangeData;
mit dieser Zeile wird natürlich sehr viel Speicher belegt und das kann dann dazu führen das Windows anfängt den Speicher auf der Festplatte auszulagern.
Ich würde diesen Wert mal auf 1.000 setzen um zu sehen, ob die Geschwindigkeit der Schleife zunimmt, oder besser einen dynamischen Array dafür verwenden, um nur so viel Speicher zu Verbrauchen wie er auch benötigt wird.

Bis bald Chemiker

mkinzler 15. Feb 2009 16:36

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Wenn schon per array dann einen dynamischen. Besser aber eine Liste oder eine Datenbank-Lösung

HaJo 15. Feb 2009 17:01

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
@mkinzler, Danke für den Hinweis zur Datenbank-Lösung!

Gerade das hier spricht dafür:
Zitat:

im Testmodus sind 45 Mitarbeiter eingepflegt
Wieviele werden es wohl am Ende sein??
Ich stelle es mir schrecklich vor, Mitarbeiterdaten im Quelltext einzupflegen :-)

Stef_One 19. Feb 2009 17:56

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
@mkinzler
Zitat:

Gerade das hier spricht dafür:
Zitat:
im Testmodus sind 45 Mitarbeiter eingepflegt

Wieviele werden es wohl am Ende sein??
Ich stelle es mir schrecklich vor, Mitarbeiterdaten im Quelltext einzupflegen Smile
also das ganze ist so aufgebaut das man die Mitarbeiter über ein Excelfile importieren kann! Wenns hoch kommt könnte das auf ganze ca.600 ansteigen!



Zitat:

mit dieser Zeile wird natürlich sehr viel Speicher belegt und das kann dann dazu führen das Windows anfängt den Speicher auf der Festplatte auszulagern.
Ich würde diesen Wert mal auf 1.000 setzen um zu sehen, ob die Geschwindigkeit der Schleife zunimmt, oder besser einen dynamischen Array dafür verwenden, um nur so viel Speicher zu Verbrauchen wie er auch benötigt wird.
@chemiker
mit diesen Datensätzen übersteuere ich die berechneten Schichten (z.b mit Urlaub/Krank/Schichten die nicht der normalen Reihenfolge entsprechen) für eine 4-5 Wochenplanung komme ich jetzt bei 45 Mitarbeitern schon auf ca. 900 einträge! Dieses Array zuverkleinern würde mir nichts bringen.

Delphi-Quellcode:
Daten : Array [1..100000] of TChangeData;

@himitsu
Zitat:

Und was ist eigentlich, wenn mal weder F, S, N oder W in SchichtList.Strings[x] vorkommt?
SchichtList gibt nur die normale Reihenfolge wieder, sollte es die Schicht von diesem System abweichen wird sie durch TChangeData
übersteuert.

mquadrat 19. Feb 2009 18:07

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Bei 600 Personen wären das 12.000 Records?! Hoffentlich suchst du dadrin nie einen bestimmten, das würde ja ewig dauern. Dazu dann noch die normale Schichtplanung.

Also da würd ich immer über ne Datenbank gehen. Wie speicherst du die Daten denn momentan eigentlich?

Chemiker 19. Feb 2009 18:58

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Hallo Stef_one,

Zitat:

Zitat von Stef_one
mit diesen Datensätzen übersteuere ich die berechneten Schichten (z.b mit Urlaub/Krank/Schichten die nicht der normalen Reihenfolge entsprechen) für eine 4-5 Wochenplanung komme ich jetzt bei 45 Mitarbeitern schon auf ca. 900 einträge! Dieses Array zuverkleinern würde mir nichts bringen.

Das kann schon sein, aber ich wollte damit nur schreiben, dass man mit einer Verbesserung der Schleife in Bezug auf Geschwindigkeit das Grundlegende Problem nicht erfasst.

Um das ganze zu vereinfachen, eine Optimierung der Schleife bringt nichts, weil Dein Ansatz grundlegend Falsch ist.

Das Mittel der Wahl ist eine Datenbank.

Bis bald Chemiker

Stef_One 19. Feb 2009 19:28

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
@mquadrat

momentan speicher ich das so:


Delphi-Quellcode:
procedure SaveMitarbeiter;//SaveFileRec;
var
  F: File of TMitarbeiter;
begin
  try
    AssignFile(F,extractfilepath(application.exename)+'\data\Mitarbeiter.dat');
    ReWrite(F);
    Write(F,Mitarbeiter);
  finally
    CloseFile(F);
  end;
end;

@Chemiker
Hmm ja Dantenbank damit habe ich mich noch nicht beschäftig, allerdings hatte ich schon nachgedacht über access zu gehn,
würd aber gern bei delphi bleiben, gibs dahin gehend eine Komponente die du mir empfehlen kannst?

mkinzler 19. Feb 2009 19:34

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Welche Delphiversion ( und Ausgabe)?

Stef_One 19. Feb 2009 19:37

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Delphi 2005 PE/mit JEDI Kompos und Indys hab ich auch installiert.

mkinzler 19. Feb 2009 19:39

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Nur leider fehlt der D2005PE die Datenbankunterstützung. Ich würde dir zur Turbo Delphi Explorer raten

Stef_One 19. Feb 2009 19:41

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
kann der das momentan erstellte project verwalten oder fang ich dann wieder von vorn an?

mkinzler 19. Feb 2009 20:03

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
Ja, TD ist ja die Nachfolgeversion von D2005

Stef_One 19. Feb 2009 20:05

Re: FOR oder WIHLE was ist schneller (Stringgrid befüllen)
 
ohh, dank dir ich guck mir das mal an! :thumb:

schöni 19. Feb 2009 20:26

Zitat:

Zitat von mquadrat
Bei 600 Personen wären das 12.000 Records?! Hoffentlich suchst du dadrin nie einen bestimmten, das würde ja ewig dauern. Dazu dann noch die normale Schichtplanung.

Also da würd ich immer über ne Datenbank gehen. Wie speicherst du die Daten denn momentan eigentlich?

Das sehe ich übrigens genauso. Jede kommerzielle Delphi Version hat doch die Datenbankkomponenten dabei zuzüglich Interbase oder, wenn es denn noch sein muss, BDE.

AUßerdem, was ist, wenn sich der Bearbeitungsablauf ändert. Hier wäre die Datenbank überlegen. Da würd ich mit der Query-Komponente arbeiten, weil dort neue Abfragen, die zum Entwurfszeitpunkt der Anwendung noch nicht bekannt waren, mit SQL zu Laufzeit gelöst werden können. Im hier vorgestellten Programm sind dann Quelltextänderungen angesagt. Wie steht es mit der Entwicklungszeit. Ist da die vorliegende Version wirklich schneller fertig?

Wenn sich jetzt Gesetze ändern und die Datenbankstruktur entsprechend angepasst werden muss?

Hab mal zu DDR Zeiten (1988) eine Wareneingangsprogramm geschrieben. Ein 1:1 Relation war genau richtig, weshalb unser Redabas (Relationales Datenbanksystem <DDR Pendant zu Dbase>) in der Version 1 gepasst hat. Umfassendere Relationen konnten erst die Nachfolgeversionen.

Damals hätte ich ein Delphi mit den Datenbankkomponenten bestens gebrauchen können. Ich hab mich mit der Kommandosprache von DBase rumgeschlagen und alles im Quelltext der DBase eigenen Kommandosprache geschrieben. Druckerausgaben, Reports...

Und hier sehe ich jetzt einen Programmierer, der Delphis Datenbankschnittstelle zur Verfügung hat und sie nicht nutzt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:26 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-2025 by Thomas Breitkreuz