Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Listen kontinuierlich aktualisieren (https://www.delphipraxis.net/182974-listen-kontinuierlich-aktualisieren.html)

michele_tedesco 1. Dez 2014 12:22

Listen kontinuierlich aktualisieren
 
Hallo Zusammen

Ich habe eine Client/Server Anwendung von Delphi 2007 zu Delphi XE5 gezügelt.

Eine Client-Funktionalität erlaubt es mehrere "Listen-Forms" (Forms mit einer StringGrid) zu öffnen, welche über eine ClientSocket gespeist werden.
Jede Liste enthält ca. 5 Spalten. Die Daten werden einmalig pro Client beim Starten des Client in eine Array von Records Daten-Struktur geladen.

Die Forms, welche in einem Client geöffnet sind, werde in einer TList verwaltet.

Wenn nun über eine TCP-Nachricht der Server eine Nachricht sendet, werden alle Clients benachrichtigt. Jeder Client interpretiert die Nachricht und in einer Schlaufe aller geöffneten Forms (TList) werden alle StringGrids Zeile für Zeile aktualisiert.
Dieses Update passiert in Sekunden-Takt. Es werden in ca. 2 Stunden ca. 30'000-Einträge gemacht.

Bei 4 Clients mit je 5 göffneten Forms, sind es 20 Forms mit einer StringGrid die pro TCP Nachricht aktualisiert werden.

Wenn diese Clients auf D2007 kompiliert werden, dann kann es schon sein dass die CPU für 2,3 Mal 1-2 Sekunden 80-90% CPU Last erzeugen. Das ist immer dann, wenn am meisten TCP-Nachrichten dicht bei einander gesendet werden.

Wenn ich die selbe Anwendung nun auch DXE5 kompiliere, ergeben sich am Anfang die ähnlichen CPU-Peaks, nur erholt sich die CPU dann bis am Ende der Verarbeitung nicht mehr und die Clients sind dann "wie eingefroren". Da die CPU-Last so weit oben ist, dass das UI nicht mehr Antwort gibt.

Wie würde man solch ein Problem heute in Delphi XE5,6 oder 7 lösen?

Danke und Gruss

Dejan Vu 1. Dez 2014 12:45

AW: Listen kontinuierlich aktualisieren
 
Optimierungspotential:
1. Die Nachrichtenverarbeitung per TCP im Hintergrund laufen lassen. Auch die Listen werden im Hintergrund aktualisiert, allerdings nicht(!) die Darstellung
2. Ein Timer aktualisiert z.B 2x pro Sekunde die Listen.
3. Die Listen sind gegen kongruete Zugriffe geschützt (TCritical Section)
4. Der Aktualisierungstimer wird nur gestartet, wenn die Liste verändert wurde.
5. Es werden nur die Zeilen im StringGrid aktualisiert, die sich auch verändert haben.
6. Aktualisierungen im StringGrid mit 'BeginUpdate'/'EndUpdate' umschließen.
7. Nur sichtbare Zeilen aktualisieren.
8. Statt StringGrid eine ListView (oder gleich ein VST) im virtual Mode nehmen.
Damit sollte die Skalierbarkeit deutlich erhöht werden.

p80286 1. Dez 2014 16:35

AW: Listen kontinuierlich aktualisieren
 
@Dejan Vu
Noch 11 und Du hast einen Grund zu feiern!

@michele_tedesco
abgesehen von den Vorschlägen, die Dejan Vu gemacht hat, sollte das Verhalten eigentlich gleich/ähnlich sein. Wie sieht es mit den Compilerschaltern aus (Range Check etc.)

Oder hast Du vielleicht zu viele (implizite) Wechsel/Konvertierungen zwischen AnsiString und (wide)String eingebaut?

Gruß
K-H

Der schöne Günther 1. Dez 2014 18:05

AW: Listen kontinuierlich aktualisieren
 
Nachdem ich bei der Suchmaschine meines Vertrauens einmal "delphi stringgrid beginupdate" eingegeben habe scheint es, dass der TStringGtrid selbst extrem langsam ist- Zumindest wenn man neue Zeilen hinzufügst.

Angeblich bringt es schon sehr viel, mittels einer WM_SETREDRAW das Ding einzufrieren und erst nachdem alles fertig ist wieder aufzutauen.

himitsu 1. Dez 2014 18:41

AW: Listen kontinuierlich aktualisieren
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1281867)
Nachdem ich bei der Suchmaschine meines Vertrauens einmal "delphi stringgrid beginupdate" eingegeben habe scheint es,

Das BeginUpdate ist dort auch besonders schön "versteckt".
http://www.delphipraxis.net/182881-c...ml#post1281804

Dejan Vu 1. Dez 2014 20:41

AW: Listen kontinuierlich aktualisieren
 
Zitat:

Zitat von p80286 (Beitrag 1281849)
@Dejan Vu
Noch 11 und Du hast einen Grund zu feiern!

Ich hab auch so einen Grund, zu feiern. Aber wie kommst Du auf 11?

Das Problem ist hier TCP bzw. das ständige Redraw der Grids.
Ich hatte Ähnliches mit 10 Threads, die einkommende TCP-Messages in 10 TMemos geloggt haben. Alles schön entkoppelt und ohne Synchronize, dafür mit Messages. Also imho optimal (halbwegs), jedenfalls besser als mit 'Synchronize' . Trotzdem fror die Anwendung immer wieder ein. Grund: Der Hauptthread wurde so dermaßen mit redraw-messages (und meinen eigenen) geflutet, das für normale Aktionen keine Zeit mehr war.

Ich habe dann einfach das ständige Aktualisieren der Memos deaktiviert. Wenn tausende Messages pro Sekunde ankommen, ist es doch wurscht, ob ich die alle sehe. Also: Daten in einen Ringbuffer und 2x pro Sekunde aktualisieren. Fertig.

Sir Rufo 1. Dez 2014 20:53

AW: Listen kontinuierlich aktualisieren
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ja wie kommt der auf 11, wo es doch nur noch 10 sind ;)
Anhang 42227

Dejan Vu 2. Dez 2014 07:03

AW: Listen kontinuierlich aktualisieren
 
:wall: Noch ein paar sinnlose Beiträge mehr und ich kann mir endlich die Pappnase und das Hütchen aufsetzen :party:

michele_tedesco 4. Dez 2014 08:14

AW: Listen kontinuierlich aktualisieren
 
Hallo Zusammen

@DejanVu und @himitsu, vielen Dank.
Ich habe bereits mehr als ein Optimierungschvorschlag eingebaut/umgebaut und es scheint schon Mal weniger Resourcen zu benutzen :cheer:

Vorallem BeguinUpdate und der Aktualisierungs-Timer haben sehr geholfen!

Gruss

generic 5. Dez 2014 10:01

AW: Listen kontinuierlich aktualisieren
 
Zitat:

Zitat von michele_tedesco (Beitrag 1281806)
Client interpretiert die Nachricht und in einer Schlaufe aller geöffneten Forms (TList) werden alle StringGrids Zeile für Zeile aktualisiert.
Dieses Update passiert in Sekunden-Takt. Es werden in ca. 2 Stunden ca. 30'000-Einträge gemacht.

Klingt nach vielen Daten...

Denk mal über einen Ansatz nach, dass *nur* die Änderungen möglichst kompakt übertragen werden.
Wenn du für jede Zeile ein TCP-Paket schickst, wird das sicherlich viel unnötigen Traffic machen.

Vorschlag:
Serverseitig machst du an jedem Datensatz Integer-Feld dran - nennen wir es Transaktion.
Der Server hat eine Transaktionsnummer. Immer wenn eine Aktualisierung an Daten durchgeführt wird, wird anschließend diese Nummer erhöht.
Die aktuelle Nummer wird an allen *veränderten* Datensätzen in das neue Feld geschrieben.

Startet nun ein Client, sagt er dem Server gibt mir alle Zeilen welche eine Transaktionsnummer größer 0 haben. Dieses entspricht einen vollen Ladevorgang -> Erstbefüllung.

Die höhste Transaktionsnummer der Daten merkt sich der Client.

Bei den nächsten (Teil-) Aktualisierung fragt der Client den Server nach allen Datensätzen/Zeilen die eine Transaktionsnummer haben, welche größer als die gemerkte ist.

Mit dieser Technik kannst du nur Teile übertragen und die Pakete etwas effizienter Nutzen.
Der Client muss weniger Daten verarbeiten, da nicht immer ein Full-Update durchgeführt wird.
Wenn keine Daten verändert wurden, werden keine Daten übertragen.

Alternativ könnte man über Multicast, MessageQueues nachdenken.


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:34 Uhr.
Seite 1 von 2  1 2      

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