AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Ansatz für Task-Queue Sequenz

Ein Thema von Rollo62 · begonnen am 17. Jun 2015 · letzter Beitrag vom 7. Jul 2015
Antwort Antwort
Seite 1 von 2  1 2      
Rollo62

Registriert seit: 15. Mär 2007
4.093 Beiträge
 
Delphi 12 Athens
 
#1

Ansatz für Task-Queue Sequenz

  Alt 17. Jun 2015, 11:55
Hallo zusammen,

für die Separierung von Aufgaben in Taksk möchte ich anonyme Methoden benutzen, und diese dann mit
kleinen Delays hintereinander ausführen.
Ich möchte einfach eine leicht zu handhabende Funktion um innerhalb von Actions und Events eine
Ausführung "Ohne externen Timer" zu starten, wenn man noch innerhalb der eigentlichen EventFunktion ist.

Ein Beispiel wäre FireMonkey TabControl -> OnTabChange. Wenn in der OnTabChange ein weiterer
TabChange ausgelöst werden soll wird das ignoriert, weil das nach Verlassen des EventFunktion wieder rückgesetzt wird.
Also müsste ich EventFunktion erst beenden lassen, und dann von ausserhalb den TabChange machen den ich möchte.


Ich habe einen ersten Versuch mit TTask und TTread.Synchronize gemacht, siehe hier:

Code:
// Procedure sequence of syncronized Tasks
// iDelay determines a delay before or after the Task, to separate external Events
// -iDelay means Delay before each Task, already before first
// +iDelay means Delay after each Task, the first is w/o delay
procedure Task_Sequence_SyncAndDelayed(iDelay : Integer; const aProcs : TS4Proc_Delegate_Array);
begin

   TTask.Create(procedure ()
                var
                  I  : Integer;
                  tsk : ITask;
                begin


                   for I := 0 to Length(aProcs)-1 do
                   begin

                     tsk := TTask.Create(procedure ()
                                  begin
                                     if iDelay < 0 then
                                       Sleep(Abs(iDelay)); // xx milliseconds

                                     TThread.Synchronize(nil, TThreadProcedure(aProcs[I]) ); //Interact with UI

                                     if iDelay > 0 then
                                       Sleep(Abs(iDelay)); // xx milliseconds

                                  end).Start;

                     tsk.Wait();

                   end; // End loop

                end).Start;

end;

Aufgerufen werden soll sas dann wie folgt: Es können mehrere Aufgaben hintereinandergeschaltet werden, falls nötig.

Code:
        Task_Sequence_SyncAndDelayed(-500,
                                       [
                                          // 1st Task
                                          procedure
                                          begin
                                            //Interact with UI
                                            FFrmNotebook.ClearHeader( True );
                                            ChangeTabActionViewNotebook.ExecuteTarget(ChangeTabActionViewNotebook);
                                          end,
                                          // 2nd Task, separated by Delay
                                          procedure
                                          begin
                                            //Interact with UI
                                            ChangeTabActionViewProject.ExecuteTarget(ChangeTabActionViewProject);
                                          end
                                       ]);

Das scheint so zu funktionieren, aber ich bin nicht sicher ob es auch grundsätzlich in Ordnung ist das so zu machen.
Womöglich gibt es Probleme mit Delphi, Firemonkey, iOS, MAXOS, Android, etc.
Vielleicht gibt es ja auch schon eine Task-Queue die durch Delays getrennt wird, welche ich nicht gefunden habe.

Wäre schön eure Meinung dazu zu bekommen.

Rollo
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.143 Beiträge
 
Delphi 10.3 Rio
 
#2

AW: Ansatz für Task-Queue Sequenz

  Alt 17. Jun 2015, 12:16
Falscher Ansatz - würde ich sagen -

Das ist ein klassischer Ansatz für Sir Rufo's Idleworker...

Hole dir

  TMessageManager.DefaultManager.SubscribeToMessage( TIdleMessage, HandleIdleMessage ); Dann nimm eine TaskListe wie

  FTasks: TQueue<TProc>; In die Queue geht es mit

Delphi-Quellcode:
procedure TIdleWorker.Execute( Action: TProc );
begin
  FTasks.Enqueue( Action );
end;
und die Verarbeitung geht so:

Delphi-Quellcode:
procedure TIdleWorker.HandleIdleMessage( const Sender: TObject; const m: TMessage );
var
  LTask: TProc;
begin
  if FTasks.Count > 0 then
    begin
      LTask := FTasks.Dequeue( );
      LTask( );
    end;
end;
Ich habe "ALLE" Application.Processmessages aus meiner App entfernt...
Warum waren die da drin?

Beispiel:

Delphi-Quellcode:
Procedure TForm1.Button1Click(Sender : TObject);
begin
  Application.Processmessages;
  MachewasLanges;
end;
Weil Firemonkey sonst NIE die Click oder Select Animation abspielt.. (Farbe setzen usw.)
Daher sieht der User keine Reaktion..

Daher mache ich meine Verarbeitung nur noch im Application.OnIdle -> der ruft die obere Message auf...

Dann sieht es so aus:

Delphi-Quellcode:
Procedure TForm1.Button1Click(Sender : TObject);
begin
  TIdleWorker.default.Execute(Procedure
    begin
      MachewasLanges;
    end;
end;
Bedeutet die App ist sofort wieder im MainThread und kann die ganze UI aufbauen... Und wenn alles fertig ist meine Routine aufrufen...

So habe ich alles umgestellt...

Mavarik
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.093 Beiträge
 
Delphi 12 Athens
 
#3

AW: Ansatz für Task-Queue Sequenz

  Alt 17. Jun 2015, 12:24
Hallo Mavarik,

dankesehr für die Vorschläge.
Habe mir schon gedacht das es was in Richtung Enqueue geben müsste.

Das mit Application.ProcessMessages sehe ich auch so, deshalb hoffe ich das Delay() entsprechend
sauber in allen OS umgesetzt wird.

Ich möchte aber eben noch ein Delay mit einbauen, um die Ausführungen zu Verzögern, wenn ich statt Delay
einen Performancetimer oder ähnliches nehme mache ich eine Loop die auch viel Rechenzeit für nichts verwendet.

Ist da ProcessMessages nicht das kleinere übel ?

Oder gibt es eine DelayFunktion die ohne ProcessMessages auskommt ?

EDIT:
Übrigens
Zitat:
Application.Processmessages;
MachewasLanges;
Mir geht es eher um die Delays, als um etwas Langes zu machen, dafür würde ich schon eine andere Struktur benutzen.

Rollo

Geändert von Rollo62 (17. Jun 2015 um 12:28 Uhr)
  Mit Zitat antworten Zitat
Photoner

Registriert seit: 6. Dez 2012
Ort: Nürnberg
103 Beiträge
 
Delphi 10.1 Berlin Starter
 
#4

AW: Ansatz für Task-Queue Sequenz

  Alt 17. Jun 2015, 12:47
Man kann dem IdleWorker noch zwei Arrays verpassen:

Delphi-Quellcode:
FTasks : T??? // 0..n
EarliestStartArr : Array of Integer // 0..n (GetTickCount+gewünschtes Delay)
WaitAfterExecArr : Array of Integer // 0..n
Delphi-Quellcode:
procedure TIdleWorker.Execute( Action: TProc ; EarliestStart : Integer; WaitAfterExec : Integer);
begin
  FTasks.Enqueue( Action );
  Setlength(EarliestStartArr,Length(EarliestStartArr )+1);
  EarliestStartArr[High(EarliestStartArr )] := EarliestStart;
  Setlength(WaitAfterExecArr ,Length(WaitAfterExecArr)+1);
  WaitAfterExecArr[High(WaitAfterExecArr)] := WaitAfterExec;
end;
Delphi-Quellcode:
procedure TIdleWorker.HandleIdleMessage( const Sender: TObject; const m: TMessage );
var
  LTask: TProc;
begin
  if FTasks.Count > 0 then
    begin
      LTask := FTasks.Dequeue( );
      while GetTickCount<EarliestStartArr[??] do sleep(1);
      LTask( );
      sleep(WaitAfterExecArr[??])
      // hier noch die Arrays anpassen: x[??] löschen und Längen dementsprechend anpassen
    end;
end;
Nicht getestet, nur im Browser getippt.
Chris

Geändert von Photoner (17. Jun 2015 um 12:50 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Ansatz für Task-Queue Sequenz

  Alt 17. Jun 2015, 12:48
Du willst also etwas nach einer bestimmten Zeit im MainThread abarbeiten lassen.

Dann nimmt man sich eine Liste und fügt diese Methoden dort ein. Die Liste sortiert dann die Einträge nach den Delay-Werten (bzw. dem Zeitpunkt, ab wann diese Methode ausgeführt werden soll).

Jedes Mal, wenn die Anwendung in den Idle-Zustand kommt, dann führt man die einfach die Methode aus, die jetzt an der Reihe ist.

Der Vorteil dabei ist, dass du damit garantieren kannst, dass diese Methoden auch ausgeführt werden. Bei den Tasks geht das eben nicht (wenn man eine bestimmte Grenze überschreitet). Denn je nach CPU-Anzahl sind immer nur eine begrenzte Anzahl an Worker-Threads aktiv. Und wenn du nun dort einen Haufen Tasks einstellst, die mal eben 5 Minuten warten sollen und dann einen Task, der 10 Sekunden warten soll, dann kann es dir u.U. sogar passieren, dass dein 10 Sekunden Task erst nach ein paar Stunden aufgerufen wird!

Die TPL funktioniert dort gut, wo ich Tasks habe, die auch ihre echte Arbeit aufnehmen, wenn diese gestartet wurden und diese Arbeit auch ein Anfang und Ende hat. Langläufer oder Langschläfer haben in der TPL nichts zu suchen, denn dafür ist diese nicht gebaut.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: Ansatz für Task-Queue Sequenz

  Alt 17. Jun 2015, 12:50
@Photoner

So definitiv nicht, sondern eine Liste aus so einem kleinen Record:
Delphi-Quellcode:
TWaitMethod = record
  Proc : TProc;
  ExecuteAfter : TDateTime;
end;
Eine Queue ist hier nicht mehr möglich, da man die Verarbeitung anhand der Startzeiten steuern möchte.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Photoner

Registriert seit: 6. Dez 2012
Ort: Nürnberg
103 Beiträge
 
Delphi 10.1 Berlin Starter
 
#7

AW: Ansatz für Task-Queue Sequenz

  Alt 17. Jun 2015, 12:53
@Sir Rufo

Stimmt. Das würde blockieren.

Wie wäre es damit:

In HandleIdleMessage müsste man erst die EarliestStart Liste durchgehen und die erste Methothe die die Bedingung erfüllt wird ausgeführt. Erfüllt das keine, dann ists kein Problem mehr
Chris

Geändert von Photoner (17. Jun 2015 um 12:56 Uhr)
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.093 Beiträge
 
Delphi 12 Athens
 
#8

AW: Ansatz für Task-Queue Sequenz

  Alt 17. Jun 2015, 12:55
Hallo Photoner,

danke für den Vorschlag.
Aber da ist auch ein Sleep() drin.

Wenn ich Mavarik richtig verstehe vermutet er darin ein Application.ProcessMessages, und das möchte er mit Recht verbannen.

Da bleibt wohl nur mit GetTickCount zu selber zu zählen.
Aber ist GetTickCount Platform-Spezifisch ?


@Sir Rufo

Ja, so ungefähr. Es sollte aber auch ein möglichst einfache Syntax sein.
Also am Beispiel ChangeTabAction.ExecuteTarget(), da diese Zeile im Aufrufe Probleme macht möchte ich die etwas verzögern damit es nach
dem Aufrufer ausgeführt wird.
- ist nicht unbedingt etwas Langes
- soll aber kein Syntax-Monster werden
- Wenn möglich auch gleicht mehrere solcher Prags nacheinander schalten können, um z.B. Tabs mehrecht gleiten zu lassen

Rollo
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.143 Beiträge
 
Delphi 10.3 Rio
 
#9

AW: Ansatz für Task-Queue Sequenz

  Alt 17. Jun 2015, 13:01
Du willst doch Dein Delay nur deswegen machen, damit das Tabchange usw. noch ausgeführt wird.. oder habe ich das falsch verstanden?

Da bei sowas die UITask beschäftigt ist, wird der onIdle sowieso nicht aufgerufen und warten ganz automatisch...

Der Delay müsste ja processorabhängig sein.

Mavarik
  Mit Zitat antworten Zitat
Photoner

Registriert seit: 6. Dez 2012
Ort: Nürnberg
103 Beiträge
 
Delphi 10.1 Berlin Starter
 
#10

AW: Ansatz für Task-Queue Sequenz

  Alt 17. Jun 2015, 13:04
Sleep function

https://msdn.microsoft.com/en-us/lib...=vs.85%29.aspx

kernel32.dll

"Suspends the execution of the current thread until the time-out interval elapses."

System.Sysutils gibt noch jede Menge Fktn. her. Stichworte:
  • Now
  • GetTime
Chris
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:57 Uhr.
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