Wie kann ich Overhead minimieren, wenn Nachrichten in einer langen Schleifenverarbeitung

StackOverflow https://stackoverflow.com/questions/3402824

  •  25-09-2019
  •  | 
  •  

Frage

Ich habe einige lange, aber einfache Schleifen in meinem Delphi-Programm bekommt, dass Mai Schleife Millionen Mal und einige Sekunden dauern, auszuführen. Der Code innerhalb der Schleife ist sehr schnell und wird optimiert. Es dauert nur so lange, weil es so viele Male durchgeführt wird.

z.

Screen.Cursor = crHourGlass;
R := FirstRecord;
while R <> nil do begin
  { do something simple with R.Value }
  R := R.NextRecord;
end;
Screen.Cursor := crDefault;

Nun möchte ich nicht mein Programm nicht mehr reagiert werden, so dass ich eine Application.ProcessMessages innerhalb der Schleife hinzufügen möchten. Aber ich mag auch die zusätzlichen Erklärungen meine Schleife so wenig wie möglich zu verlangsamen.

Ich verfolge eine verkettete Liste, so dass ich nicht einmal eine Zählvariable zur Verfügung haben kann und müßte man hinzufügen, wenn ich Intervalle wollte. Oder ich muss einen Timer hinzuzufügen, sondern müssen über die Zeit zu minimieren.

Wie soll ich dies implementieren den Aufwand zu minimieren, die hinzugefügt wird?


Fazit:

Im Moment mache ich so etwas wie APZ28 Antwort.

Aber es sieht aus wie langfristig soll ich eine Art Einfädeln implementieren, dies zu umgehen. Vielen Dank für diesen Hinweis, weil ich dachte, dass Application.ProcessMessages der einzige Weg, es zu tun.

War es hilfreich?

Lösung

Kann setzen Sie die Arbeit Schleife in einem Thread, die Befreiung der Haupt-Thread für die GUI-Schleifenverarbeitung auf.

Andere Tipps

Legen Sie es unter Faden ist nicht trival da es Sperre Freigabe-Ressource, wenn eine erforderlich ist. Ein guter Trick ist, einen Zähler mit nach Anzahl der Schleifenverarbeitung, Call Process

var
  LoopCounter: Integer;

LoopCounter := 0;
R := FirstRecord;
while R <> nil do begin
  Inc(LoopCounter);
  if (LoopCounter >= ???) then
  begin
    LoopCounter := 0;
    Application.ProcessMessages;
  end;

  { do something simple with R.Value }
  R := R.NextRecord;
end;

Ich würde stimmen auch für einen Thread oder so etwas wie Anreas' AsyncCalls . Um den Benutzer zu verbieten, tun alle nicht erlaubten Aktionen während der Zeit benötigt, können Sie ein Flag gesetzt, wenn die Routine beginnt und zurücksetzen, wenn es endet (Sie müssen aktualisieren Screen.Cursor sowieso). Der Haupt-Thread kann dieses Flag überprüfen und deaktivieren Sie alle betroffenen Aktionen in ihrem OnUpdate Ereignis.

Die beste Möglichkeit ist die Schleife in ihren eigenen Arbeitsthread zu bewegen, so der Haupt-Thread nicht blockiert ist, dann müssen Sie nicht Anruf Process () überhaupt.

Wenn Sie jedoch die Schleife im Hauptthread tun müssen, dann können Sie verwenden MsgWaitForMultipleObject (), um festzustellen, wann Process () aufzurufen, das heißt:

Screen.Cursor = crHourGlass; 
R := FirstRecord; 
while R <> nil do begin 
  { do something simple with R.Value } 
  if MsgWaitForMultipleObjects(0, nil, False, 0, QS_ALLINPUT) = WAIT_OBJECT_0 then
    Application.ProcessMessages;
  R := R.NextRecord; 
end; 
Screen.Cursor := crDefault; 

Alternativ mit PeekMessage ():

var Msg: TMsg;

Screen.Cursor = crHourGlass; 
R := FirstRecord; 
while R <> nil do begin 
  { do something simple with R.Value } 
  if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
    Application.ProcessMessages;
  R := R.NextRecord; 
end; 
Screen.Cursor := crDefault; 

Alternativ mit GetQueueStatus ():

Screen.Cursor = crHourGlass; 
R := FirstRecord; 
while R <> nil do begin 
  { do something simple with R.Value } 
  if GetQueueStatus(QS_ALLINPUT) <> 0 then
    Application.ProcessMessages;
  R := R.NextRecord; 
end; 
Screen.Cursor := crDefault; 

Eine Frage zu entscheiden, ob Ihre Anwendung fortgesetzt werden kann, bevor Sie die Antwort auf das haben, was die Schleife Berechnung ist. Wenn es nicht kann, dann ist es nicht viel Sinn in der Anwendung sein „responsive“. Wenn Sie versuchen, einen Fortschrittsbalken oder etwas zu aktualisieren, können Sie .Repaint auf dem Steuerelement enthält der Fortschrittsbalken jede bestimmte Anzahl von Iterationen rufen die Statusleiste zu bewirken, neu streichen.

Wenn kann die Anwendung auch weiterhin, zumindest für eine Weile, dann in einem Thread den Code setzen ist eine gute Idee.

in einem Thread den Looping-Code zu platzieren, ist wahrscheinlich sowieso vernünftig, vor allem, wenn Sie Dinge tun wollen wie möglicherweise Abbruch der Verarbeitung. Wenn Sie noch nie Threads verwendet haben, bevor, es ist ein bisschen eine Lernkurve, aber für eine einfache Schleife wie Sie beschreiben, es gibt viele Beispiele im Web.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top