AGB  ·  Datenschutz  ·  Impressum  







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

Datenübergabe aus Thread in MainForm

Ein Thema von backdraft · begonnen am 10. Okt 2022 · letzter Beitrag vom 11. Okt 2022
Antwort Antwort
backdraft

Registriert seit: 19. Apr 2005
Ort: Hückeswagen
333 Beiträge
 
Delphi 11 Alexandria
 
#1

Datenübergabe aus Thread in MainForm

  Alt 10. Okt 2022, 20:32
Hallo zusammen,
ich brauche mal einen Tipp für mein Problem.

Ich nutze die OmniThreadLib um Daten in einem Task aus einer Datenbank zu laden und sende diese dann per Message an die MainForm.
Diese zerlegt die Daten und zeigt sie auf dem Bildschirm an.
Der Task sammelt die Daten 100ms und sendet diese dann als Array of Variant.

Ich sende an den Task eine Nachricht "Lade mir bitte diese Daten" und dann führt der Task diese Aktion aus.
Ist er fertig wartet er auf den nächsten Befehl.

Auf der Maske ist noch ein "Stop" Knopf, der dem Task meldet, dass die aktuelle Aktion abgebrochen werden soll.

So weit so gut, klappt alles wunderbar.

Aber, wenn ich die Datenbank lokal betreibe liefert der Task die Daten scheinbar so schnell, dass ich überhaupt keine Chance habe den Stop Knopf zu drücken, da der Mainthread 100% Auslastung hat mit dem verarbeiten der Botschaften.

Es hilft, wenn ich eine Wartezeit einbaue, dass nach jedem Senden ein bisschen gewartet wird, aber das ist keine befriedigende Lösung.

Eine Nachricht an den Task senden, hilft auch nicht, da er den Befehl in einer Message bearbeitet und erst wieder die nächste Anfrage bearbeitet, wenn er mit der aktuellen Aufgabe fertig ist. Um das nutzen zu können, müsste ich das Konzept hier umbauen, was ich eigentlich nicht vor habe.

Schön wäre es, wenn ich irgendwie erkennen könnte, dass ich genau in diese Situation laufe.
Oder ist es sinnvoll, dass der Task so lange wartet, bis der MainThread die aktuelle Aktion verarbeitet hat?
Gibt es da irgendwas integriertes in der Lib? Bis jetzt habe ich leider nichts gefunden.

LG
Oliver
Oliver
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.142 Beiträge
 
Delphi 12 Athens
 
#2

AW: Datenübergabe aus Thread in MainForm

  Alt 10. Okt 2022, 20:45
Warum so schnell?
Wer liest denn 10 Mal jede Sekunde alles?
sekündlich?


Oder gibt dem Hauptthead erst wieder was, wenn er fertig ist.
z.B. der Hauptthread gibt Bescheid, wenn er fertig ist und x Millisekunden/Sekunden später wird die neue Nachricht geschickt

* der Hauptthread nutzt ein Event, um dem Thread Bescheid zu sagen

* oder der Hauptthread schreibt in eine Timer-Variable, wann er fertig ist ... x Sekunden nach dieser Zeit sendet der Thread frühestens wieder (er setzt dann diese Variable vor dem Senden auf 0, damit er weiß, das schon was raus ist)
-> Variable <> 0 und Variable+X < Aktuell -> Neues übergeben

* ODER du gibst nichts an den Hauptthread, sondern er holt es sich, wenn er Zeit hat.
Da du eh schon im Array sammelst, hast du den Cache für die Übergabe ja schon fertig.
(wenn nicht immer Daten vorhanden sind, dann kann der Thread ein TEvent setzen, damit der Hauptthread mitbekommt, wann er nach neuen Daten schauen soll ... oder alternativ nur "einmalig" eine "Hallo"-PostMessage, wenn das Array grade seinen ersten (neuen) Eintrag bekommt)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
backdraft

Registriert seit: 19. Apr 2005
Ort: Hückeswagen
333 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Datenübergabe aus Thread in MainForm

  Alt 10. Okt 2022, 21:31
Danke erstmal für die Tips. Ideen hab ich auch, wie wann es mit Variablen macht, die Task und Mainform austauschen. Die eigentliche Frage war, gibt es was fertiges in der OmniThreadLib, wie z.B das mit dem CancelationToken. z.b ein PausedToken… gibt’s nicht, hätte ich sonst schon gefunden.

Also quasi eine einfache Möglichkeit, was zu nutzen, was die Lib bietet.
Oder gibt es in der Lib die Möglichkeit zu sagen, warte nach dem Senden der Nachricht, bis diese verarbeitet wurde.
Ich möchte das Rad nicht dazuerfinden, wenn es schon da ist.
Wie würde man sowas mit der OTL umsetzen, frage ich mich.

Es auf 1 Sekunde zu verlängern bringt auch nix, dann braucht er 10 mal so lang zum verarbeiten der Daten. Das Problem sind glaube ich nicht die Anzahl Nachrichten, sondern die Maße der Daten.
Ich hab am Intervall schon rumgespielt, best use case ist zwischen 100 und 250ms. Bei externen Datenbanken klappt es so am besten. Lokal DB klappt oder nicht kommt halt immer darauf an, was der Rechner sonst noch so treibt und was er gerade aus der DB anzeigen soll, hab ich das Gefühl. Mal klappt’s, mal nicht.

Ich habe bis jetzt sowas auch immer alles selbst gemacht, und wollte aber in dem Projekt mal die OTL nutzen. Deswegen meine Frage.
Oliver

Geändert von backdraft (10. Okt 2022 um 21:50 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.142 Beiträge
 
Delphi 12 Athens
 
#4

AW: Datenübergabe aus Thread in MainForm

  Alt 10. Okt 2022, 22:14
Zitat:
Es auf 1 Sekunde zu verlängern bringt auch nix, dann braucht er 10 mal so lang zum verarbeiten der Daten.
Da has du doch schon das eigentliche Problem?

Die Arbeit im Hauptthread muß weniger sein, als wie die Zeit bis zu den nächsten Daten.


entweder die Arbeit beschleunigen,
oder weniger Daten senden

oder z.B. statt Array eine threadsave Queue/Liste, wo sich der Hauptthread so schnell/langsam Daten raus holt, wie er kann
und das Mehr an Daten drin bleibt, bis er Zeit hat.
Das geht natürlich nur um "Spitzen" abzufangen oder später nachzuarbeiten, aber insgesamt weniger Daten eintreffen, als über die ganze Zeit maximal verarbeitet werden kann.
bzw. wenn es irgendwann reicht, nachdem der Thread mal fertig ist und danach der Hauptthread das dann in Ruhe fertig machen kann.





Ich hab mich grade realtime in Windows-Event-Tracing reingehängt
und für die ersten Versuche einfach nur aus dem Thread in ein Memo geschrieben ... nach ner gewissen kurzen Zeit passiert es dann immer wieder, das Alles hängt und mir Events verloren gehen, weil der Lese-Thread ebenfalls zum Stocken kommt.

Ich könnte zwar auch auf LogFile(s) umstellen, aber das verursacht wieder andere Probleme (z.B. das FestplattenLog loggt sich selber)
Nja, im Grunde hab ich mir jetzt eine Queue-ListeArray gebastelt, weil bei der Menge an Durchsatz die bestehenden Listen wieder ihre Problme haben. (Speichermanagement und zu häufiges Umkopieren)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
backdraft

Registriert seit: 19. Apr 2005
Ort: Hückeswagen
333 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Datenübergabe aus Thread in MainForm

  Alt 11. Okt 2022, 19:34
Zitat:
Es auf 1 Sekunde zu verlängern bringt auch nix, dann braucht er 10 mal so lang zum verarbeiten der Daten.
Da has du doch schon das eigentliche Problem?
Ja und nein.
Die lokale DB schafft einfach mehr Daten herbei, als der MainThread verarbeiten kann.
Deswegen habe ich das Intervall auf 100ms gesetzt.

Mit einer RemoteDB kommen pro 100ms ca. so viele Daten an, dass der MainThread diese in weniger als 5ms verarbeiten kann.
In der Regel kommen hier maximal 500k.

Bei der lokalen dauert es manchmal mehr wie 100ms, somit kommt er dann in den Loop, dass er nicht mehr Luft hat in der App auf Benutzeraktionen zu reagieren.
Würde der Thread mit dem Senden einer weiteren Nachricht warten, bis der MainThread 10ms Luft hatte wäre alles in Ordnung.

Wir reden aber auch von 5MB, die der Thread in 100ms zerlegen muss.
Das sind einfach sehr viele Daten.
Binary Daten werden auch auf der HDD zwischengespeichert.
Ich habe eine NVME, es gibt sicherlich aber auch noch HDD Benutzer. Somit dauert das Schreiben hier auch wieder länger.

Je höher das Intervall auch ist, desto länger Freezed die Anwendung ja auch bei der Verarbeitung von einem Block.
Deswegen passt 100ms ganz gut, da merkt der Anwender in der Regel nix... In der Regel aber halt nur

Ich habe auch eine Datenpool Klasse die Threadsafe Daten aus dem Thread aufnehmen kann und im MainThread anzeigen kann.
Als Darstellung nutze ich den VirtualStringTree.
Jede Zelle die er zeichnet, setzt eine Sperre auf den Pool, was auch nicht so performant ist.

Letztendlich habe ich mich aktuell dazu entschieden, die Daten via Message zu übertragen, weil die Performance dabei einfach besser ist und ich nicht so viele Locks produziere. Der Austausch der Daten via TOmniValue funktioniert hervoragend und auch sehr performant.

Wir reden hier generell vom Zeiten, die mich stören.
Der Endanwender wäre mit beiden Lösungen sicherlich zufrieden.

Vom Prinzip stört mich einfach, dass hier ein Bottleneck ist, was ich nicht beziffern kann.
Ich kann nur "meinen Computer" als Basis für die Zeit nehmen.

Aus unserer Diskussion schließe ich aber, dass es scheinbar nichts in der OTL gibt.

Eine Boolean Variable "Paused" im Task würde ja das Problem schon lösen, sowas werde ich sicherlich auch einbauen.

Danke für Deine Hilfe ...
Oliver

Geändert von backdraft (11. Okt 2022 um 19:39 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.142 Beiträge
 
Delphi 12 Athens
 
#6

AW: Datenübergabe aus Thread in MainForm

  Alt 11. Okt 2022, 21:36
Ja genau.

Wenn dein Hauptthread nur so viel Daten aus dem Thread nimmt, wie er verarbeiten kann und dann immernoch etwas Zeit hat,
oder er nimmt sich z.B. 20 Dinge aud dem Array/Queue raus und macht dann immer mal einen kurzen Sleep Delay)
dann läuft der Cache (dein Array/Queue) zwar langsam voll, wenn mal zu viel rein kommt, aber das Programm reagiert immernoch.

Andersrum kann der Thread aber auch langsamer werden, bzw. immer mal kurz pausieren, wenn der Hauptthread nicht mehr kann.


Oder kombiniert ... der Hauptthread macht so schnell wie er kann (nimmt sich z.B. alle 100ms so viel raus, wie er in weniger als dieser Zeit schafft) und der Thread pausiert, wenn ihm der Cache (Array/Queue) viel zu voll wird.




ODER

Es verarbeitet nicht der Hauptthread, sondern ein weiterer Thread,
dann reagiert das Programm auch immer, weil der Hauptthread ja nichts anderes macht, also mit dir zu reden und auf dich zu hören.

Weitergehend könnte man vielleicht dann auch gleich mehrere Threads verarbeiten lassen.
Der eine Thread holt die Daten, ein/mehrere Threads holen sich immer mal was aus der Queue/Array und ackern gleichzeitig
und der Hauptthread versorgt die GUI und gibt deine Befehle an die Threads weiter.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (11. Okt 2022 um 21:41 Uhr)
  Mit Zitat antworten Zitat
backdraft

Registriert seit: 19. Apr 2005
Ort: Hückeswagen
333 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Datenübergabe aus Thread in MainForm

  Alt 11. Okt 2022, 22:24
Ja genau.

Andersrum kann der Thread aber auch langsamer werden, bzw. immer mal kurz pausieren, wenn der Hauptthread nicht mehr kann.
Ja, das war ja eine ursprüngliche Frage.
Woher weiß ich, das der Hauptthread ausgelastet ist.
Oliver
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.142 Beiträge
 
Delphi 12 Athens
 
#8

AW: Datenübergabe aus Thread in MainForm

  Alt 11. Okt 2022, 23:02
OnIdle prüfen
TApplicationEvents

z.B. Messen wie lang ein Verarbeitungsdurchlauf dauert
GetTickCount, QueryPerformanceCounter, TStopwatch oder sonstwas

oder die CPU-Auslastung des Hauptthreads messen
MSDN-Library durchsuchenGetSystemTimes

Und da der Hauptthread ja auch nur ein Thread ist, ist es nicht verboten TThread zu benutzen, und dort gibt es seit 'ner Weile so Einiges
TThread.GetSystemTimes(...)
TThread.GetCPUUsage(...)
TThread.GetTickCount
TThread.GetTickCount64
Das sind ClassFunctions, also können genau so benutzt werden,
aber auch für Nicht-Klassenfunktionen, kann man sich einen "Dummy"-TThread geben lassen.
z.B. TThread.Current.ThreadID

Und falls jemand wissen will, wieviele Threads man machen kann
TThread.ProcessorCount
Oder man nehme etwas, was das für Einen übernimmt.
TWorkStealingQueue
TThreadPool bzw. TParallel
und vielleicht auch noch TTask statt TThread (wobei das hier ja nicht nöig wäre, aber für andere Anwendungsfälle erwähnt)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (11. Okt 2022 um 23:05 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort


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 17:12 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