![]() |
Delphi-Version: 5
MultiThreading
Moin,
Keine Ahnung ob es der richtige Bereich ist, ansonsten einfach verschieben ;) Also mein Anliegen: Ich möchte gerne beim Laden meines Programmes eine Datei auslesen und das Ergebnis in einer globalen Variablen halten. Der Vorgang dauert ggf. einige Zeit, so dass ich es gerne in einen separten Thread verlagern möchte. Das Ergebnis soll eine TStringList o.ä. sein. Es handelt sich dabei nur um die Zuordnung von einer ID zu einem String. Desweiteren möchte ich gerne bei einem Aufruf eines Formulars überprüfen, ob es neue Einträge gibt, wenn ja, dann hinzufügen, sonst nichts machen. Das funktioniert singlethread bereits alles so, wie es soll. Allerdings benötigt der Aufbau der Liste ~5 Sekunden, was zu lang ist. Und zu guter Letzt: Wenn in dem Form die Liste verwendet wird, soll geschaut werden, ob sie sich noch im Aufbau befindet, dann warten, sonst benutzen. Alle Klarheiten beseitigt? Gerne ein wenig Beispielcode damit komme ich meist besser zu recht. Danke! PS Delphi 12 |
AW: MultiThreading
Würde ich so eins zu eins in ChatGPT eingeben. "Danke!" könnte man weg lassen.
|
AW: MultiThreading
Spitzenantwort, ich nutze kein ChatGPT und habe gestern im Radio erfahren, dass Höflichkeiten bei der Verwendung sehr viele Ressourcen binden.
|
AW: MultiThreading
Kann sein das ich dich falsch verstanden habe. Was genau ist deine Frage?
|
AW: MultiThreading
Delphi-Quellcode:
Der Zugriff im Form auf MyList wartet bei Bedarf auf die Fertigstellung.
unit uMyList;
interface function MyList: TStringList; implementation uses System.Threading; var InternalFuture: IFuture<TStringList>; InternalList: TStringList; function MyList: TStringList; begin Result := InternalFuture.Value; end; initialization InternalList := TStringList.Create; InternalFuture := TTask.Future<TStringList>( function: TStringList begin Result := InternalList; for var I := 1 to 10000000 do Result.Add(I.ToString); end); finalization InternalList.Free; InternalList := nil; end; |
AW: MultiThreading
Danke Uwe, ich probiere es mal damit.
@Edelfix Wie man so etwas am geschicktesten angeht. |
AW: MultiThreading
Hat funktioniert, vielen Dank!
|
AW: MultiThreading
Wäre da nicht eher ein TDictionary<Integer,String> besser ?
|
AW: MultiThreading
Ist es inzwischen auch geworden, hatte mich zwischendurch vertan.
|
AW: MultiThreading
Ist das nicht ein Problem?
Beim Zugriff auf die MyList aus dem GUI thread heraus, würde schließlich im der GUI Thread angehalten werden(freeze), um auf die Fertigstellung des Futures zu warten. |
AW: MultiThreading
Zitat:
Zitat:
|
AW: MultiThreading
Ähm ja, ist kein richtiger Freeze, wenn die Liste nicht aufgebaut wäre, würde die Verarbeitung sie aufbauen müssen. Es ist also nur eine Teilaufgabe und die muss immer vollständig abgeschlossen sein, bevor etwas es weiter geht.
@Uwe Hast du etwas Code, damit man den Aufwand ggf. abschätzen kann? |
AW: MultiThreading
Zitat:
Delphi-Quellcode:
myform.OnClick(Sender:tObject);
Bgein MyGUIListview.enabled := false; MYGUiAnyIndicator.visibe := true; // Anzeige Animation im Hauptthread das die Liste aktualisiert wird. TThread.CreateAnonymousThread( procedure Begin var data:Tarray<TMyItemdataRec> := LoadDataForaShitLoadOfTime; // das dauert. //laden fertig ? ok call back in den GUI Thread mit ForceQueue, // es kann sein dass der Thread schneller fertig ist als die GUI // braucht um die liste disabled neu zu zeichnen und ich mag // es in der richtigen Reienfolge wegen BeginUpdate udn EndUpdate // daher ForceQueue; TThreading.ForceQueue(nil, Procedure begin MyGUIListview.BeginUpdate; MyGUIListview.clear; For Var i:integer := 0 to high(data) do AddTMyListview(data[i]); MyGUIListview.Enabled := true; MyGUIListview.EndUpdate; MYGUiAnyIndicator.visible := false; end // procedure )//TThreading.ForceQueue(nil, end // procedure ).Start; // TThread.CreateAnonymousThread( end;//myform.OnClick(Sender:tObject); |
AW: MultiThreading
Und wenn man Feedback und Fehlerbehandlung braucht so
Delphi-Quellcode:
Type
TResultData = Record Success:boolean; Error:String; Data:Tarray<TMyItemdataRec>; end; myform.OnClick(Sender:tObject); Bgein MyGUIListview.enabled := false; MYGUiAnyIndicator.visibe := true; // Anzeige Animation im Hauptthread das die Liste aktualisiert wird. TThread.CreateAnonymousThread( procedure// ThreadProcedure Begin var aResult:TResultData := LoadDataForaShitLoadOfTime; // das dauert. If aResult.Success then Begin //laden fertig ? ok call back in den GUI Thread mit ForceQueue, // es kann sein dass der Thread schneller fertig ist als die GUI // braucht um die liste disabled neu zu zeichnen und ich mag // es in der richtigen Reienfolge wegen BeginUpdate udn EndUpdate // daher ForceQueue; TThreading.ForceQueue(nil, Procedure //ForceQueue begin If aResult.Success then Begin MyGUIListview.BeginUpdate; MyGUIListview.clear; For Var i:integer := 0 to length(aResult.data)-1 do AddTMyListview(aResult.data[i]); MyGUIListview.Enabled := true; MyGUIListview.EndUpdate; MYGUiAnyIndicator.visible := false; end //If aResult.Success then else Begin Log(' LoadDataForaShitLoadOfTime:'+aResul.error); MyGUIListview.Enabled := true; MYGUiAnyIndicator.visible := false; ShowMessage(aResul.error); end //else If aResult.Success then end // procedure //ForceQueue )//TThreading.ForceQueue(nil, end // procedure// ThreadProcedure ).Start; // TThread.CreateAnonymousThread( end;//myform.OnClick(Sender:tObject); |
AW: MultiThreading
Zitat:
Delphi-Quellcode:
Bei der Verwendung prüft man dann den Status des Future auf Completed und reagiert entsprechend.
unit uMyList;
interface function MyList: TStringList; function MyListFuture: IFuture<TStringList>; implementation uses System.Threading; var InternalFuture: IFuture<TStringList>; InternalList: TStringList; function MyList: TStringList; begin Result := InternalFuture.Value; end; function MyListFuture: IFuture<TStringList>; begin Result := InternalFuture; end; initialization InternalList := TStringList.Create; InternalFuture := TTask.Future<TStringList>( function: TStringList begin Result := InternalList; for var I := 1 to 10000000 do Result.Add(I.ToString); end); finalization InternalList.Free; InternalList := nil; end; Alternativ würde es hier auch genügen lediglich den TTaskStatus öffentlich zu machen. Dann muss aber System.Threading eh schon in der uses-Anweisung stehen. Das Future bietet zudem noch die Möglichkeit des Cancel. Angenommen die Bearbeitung erfolgt auf einen Button-Click. Dann würde ich den Button mit einer TAction mit einem entsprechenden Execute-Event verbinden (sollte übrigens eh schon so sein). Im OnUpdate könnte dann sowas stehen:
Delphi-Quellcode:
Damit lässt sich der Button nur klicken, wenn die Liste fertig ist,
begin
(Sender as TAction).Enabled := (MyListFuture.Status = TTaskStatus.Completed); end; Dort ließe sich auch eine Behandlung für Canceled bzw. Exception unterbringen. |
AW: MultiThreading
Danke, das scheint überschaubar. Mal sehen wie weit ich das umsetze.
|
AW: MultiThreading
Zitat:
Also nicht von innen durch abfragen von "Terminated"? |
AW: MultiThreading
Zitat:
|
AW: MultiThreading
Zitat:
Mein Problem ist dass Futures bei mir immer die Oberfläche analten... Ich habe immer nur den GUI Thread und evtl. einen Thread der etwas im Hintergrund tut. Gibt es irgend einen Grund warum ich das lieber in Itask.run statt in einem anonymen Thread machen sollte? |
AW: MultiThreading
Zitat:
Es kommt halt immer drauf an was man alles braucht. ITask bzw. IFuture bieten z.B. auch gleich zwei Wait Overloads, mit denen man auch leicht ein non-freezing Poll implementieren kann. Vieles von dem müsste man bei einem simplen anonymen Thread noch selbst beisteuern. Nicht das das nicht auch möglich wäre. In einem mittlerweile schon über drei Jahre alten Blog Post beschreibe ich den durchaus etwas längeren Weg von Synchron zu Asynchron: ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:00 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