Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Aktualisierung und SendMessage (https://www.delphipraxis.net/177235-aktualisierung-und-sendmessage.html)

yogie 26. Okt 2013 10:26

Aktualisierung und SendMessage
 
Hallo zusammen,

ich beobachte folgenden Sachverhalt:

Von einer ersten Form (TDataModule) übertrage ich per SendMessage Daten zu einer anderen Form und lasse dort ein Element (z.B. Edit) aktualisieren. Sobald ich die Form verschiebe wird die Aktualisierung unterbrochen und läuft erst weiter wenn ich die Verschiebung beende. Mir ist schon klar, dass es an der Unterbrechung der Message-Loop liegt, aber eine richtig befriedigende Erklärung habe ich nicht. Weiterhin habe ich den Eindruck, dieses Verhalten ist nicht bei allen Objekten gleich und ich meine es hängt auch noch vom Betriebssystem ab (das geht jetzt zurück bis WIN95).

In der realen Anwendung soll die erste Form (TDataModule) Informationen über eine serielle Schnittstelle empfangen und sie dann an verschiedene Formen in der Anwendung verteilen. Bisher hatte ich dazu direkte Aufrufe von Prozeduren verwendet. Aus Gründen der besseren Trennung zwischen serieller Schnittstelle und div. Anzeigen wollte ich das jetzt ändern.

Ich wäre dankbar für eine Erklärung oder einen Tipp wie man es besser machen könnte.

jaenicke 26. Okt 2013 10:44

AW: Aktualisierung und SendMessage
 
Ich würde die Kommunikation asynchron per Thread machen und die graphische Aktualisierung synchronisieren. Das funktioniert auch beim Verschieben eines Fensters problemlos, zumindest unter Windows 8. Testbeispiel von mir eben (nicht schön, nur zum Test):
Delphi-Quellcode:
type
  TTest = class(TThread)
  protected
    procedure Execute; override;
  end;

  TForm18 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form18: TForm18;

implementation

{$R *.dfm}

procedure TForm18.Button1Click(Sender: TObject);
begin
  TTest.Create(False);
end;

{ TTest }

procedure TTest.Execute;
begin
  while not Terminated do
  begin
    TThread.Synchronize(nil, procedure
      begin
        Form18.Canvas.LineTo(Random(Form18.ClientWidth), Random(Form18.ClientHeight));
      end);
    Sleep(100);
  end;
end;

yogie 27. Okt 2013 07:45

AW: Aktualisierung und SendMessage
 
@jaenicke

Danke erstmal für den Tip.

Zwei Dinge dazu
- kann es sein, dass im Beispiel die Zeilen im Execute etwas durcheinander geraten sind?
so kann ich es jedenfalls in Delphi6 nicht machen,
ich habe es dann etwas umgebaut und zum Laufen gebracht ...

- das Problem mit der hängenden Aktualisierung läßt sich damit prima umgehen
mir geht es aber zusätzlich um eine Entkopplung zwischen der Empfänger-Form für
die seriellen Daten und den anderen Fenstern, die die Anzeigen machen.
ich habe in der Empfängerform zur Zeit eine Liste (TList) in der ich alle Anzeigefenster speichere,
bei neu einlaufenden Daten gehe ich diese Liste durch und schicke allen sichbaren Fenstern
die neuen Daten (SendMessage)

Ich habe festgestellt, dass SendMessage recht zeitaufwendig ist. Daher suche ich eine bessere
Lösung

jaenicke 27. Okt 2013 14:58

AW: Aktualisierung und SendMessage
 
Zitat:

Zitat von yogie (Beitrag 1233319)
- kann es sein, dass im Beispiel die Zeilen im Execute etwas durcheinander geraten sind?
so kann ich es jedenfalls in Delphi6 nicht machen,

Stimmt, anonyme Methoden gibt es erst ab Delphi 2009.

Zitat:

Zitat von yogie (Beitrag 1233319)
mir geht es aber zusätzlich um eine Entkopplung zwischen der Empfänger-Form für
die seriellen Daten und den anderen Fenstern, die die Anzeigen machen.
ich habe in der Empfängerform zur Zeit eine Liste (TList) in der ich alle Anzeigefenster speichere,

Genau dafür kannst du das nutzen. Du kannst dem Thread Bescheid geben und der verteilt die Aktualisierungen asynchron weiter an die weiteren Anzeigen.

Medium 28. Okt 2013 00:02

AW: Aktualisierung und SendMessage
 
Zitat:

Zitat von yogie (Beitrag 1233319)
Ich habe festgestellt, dass SendMessage recht zeitaufwendig ist. Daher suche ich eine bessere
Lösung

SendMessage() ist nicht per se langsam, sondern es wartet auf das Ende der vom Empfänger durchgeführten Aktion. Das asynchrone äquivalent dazu ist PostMessage() - das wartet nicht.

jaenicke 28. Okt 2013 04:37

AW: Aktualisierung und SendMessage
 
Nur als Hinweis, falls es relevant sein sollte: PostMessage geht nur, wenn man die Daten nach dem Abschicken nicht wieder freigibt, da die Abarbeitung später passiert.

Eine Trennung der Steuerung der GUI von der Datenverwaltung und auch der einzelnen Fenster untereinander hielte ich aber für sinnvoller als ein Fenster direkt mit den anderen Fenstern via Messages kommunizieren zu lassen.

Furtbichler 28. Okt 2013 06:13

AW: Aktualisierung und SendMessage
 
Wir hatten mal eine ähnliche Anwendung. Dort sind Daten von Messgeräten eingetroffen, sollten in die DB und parallel dazu angezeigt werden.

Wir haben es mit Threads und Messages (PostMessage) ausprobiert. Beides funktioniert gleich gut. In meinem Hinterkopf trällert aber immer noch, das man nicht mit Threads nicht um sich werfen sollte. Das kann ein Überbleibsel aus der der Steinzeit sein, aber ich finde Threads hierfür einfach oversized.

Ich würde zunächst das Observer-Pattern einführen, um Datenempfang und Visualisierung auch logisch zu entkoppeln und skalierbar zu machen.

Der Datenempfang implementiert einen Observer, an dem sich Formulare, die Daten anzeigen wollen, anmelden können.
Die Observerbenachrichtigungsschleife ist als Job eines Workerthreads implementiert, der wiederum eine Jobliste (=Queue) abarbeitet. So kann dieser Workerthread (besser : Pool) beliebige Jobs abarbeiten und das System kommt auch bei kurzzeitiger Überlastung nicht ins Schwitzen. Selbst wenn kurzzeitig sehr viele Benachrichtungen anstehen, blockiert der Observer nicht, da dann eben die Jobliste etwas voll wird...

Die Benachrichtigung an die einzelnen Subscriber (=Forms) kann nun als Postmessage verschickt werden. Das ist imho leichtgewichtiger als noch einen Thread zu starten. Allerdings sind dabei die Einschränkungen von Sebastian zu beachten. Man kann hier die Daten z.B. in eine Datenklasse mit Referenzzählung wrappen (Stichwort: Interface) oder Strings verwenden (z.B. bei einem Logger), der die Referenzzählung auch eingebaut hat.

Das generelle Problem ist hier, das bei Überlastung die Messagequeue der einzelnen Subscriber zu voll werden könnte. Das muss man im Einzelnen bewerten, ob das eine Rolle spielt und wie man damit umgehen kann bzw. soll.

jaenicke 28. Okt 2013 07:59

AW: Aktualisierung und SendMessage
 
Zitat:

Zitat von Furtbichler (Beitrag 1233358)
In meinem Hinterkopf trällert aber immer noch, das man nicht mit Threads nicht um sich werfen sollte. Das kann ein Überbleibsel aus der der Steinzeit sein, aber ich finde Threads hierfür einfach oversized.

Ob der Overhead der Messagebehandlung da wirklich so viel geringer ist?

Messages sind jedenfalls gerade bei größerem Datenaufkommen ungeeignet, da alles über einzelne Nachrichtenwarteschlangen läuft. Wenn diese dann zu stark belastet werden, merkt man das an einer etwas träge auf Eingaben reagierenden Anwendung, da die dazu gehörenden Nachrichten entsprechend langsamer behandelt werden können. Zudem kann es sein, dass eine Nachricht länger braucht bis sie abgearbeitet wird und so die Aktualisierung aller Fenster laggt.

Davon ganz abgesehen kann man mit Messages erst einmal nur zwei Zahlenwerte schicken. Alles andere läuft dann als Pointer- und Speicherspielerei. Ein Thread hingegen kann typsicher und sauber direkt mit den Daten arbeiten, diese aufbereiten und gezielt an die passenden Empfänger weitergeben.

yogie 28. Okt 2013 18:37

AW: Aktualisierung und SendMessage
 
vielen Dank!
Das ist genau die Art Beiträgen die mich weiterbringen.
(keine Ironie!!) Man ist als Einzelkämpfer immer dankbar,
wenn mal Anregungen mit einem anderen Blickwinkel kommen.
Sonst kopiert man nur immer wieder die Vorgehensweise,
die man schon vor 5 Jahren entwickelt hat.

@Furtbichler : Diese Ausführungen sind (zumindest für mich)
schon ein ziemlich großes Geschütz, trotden danke für die
ausfühliche Antwort. Ich werde das mal durchgehen und
schauen, was davon in meinem Fall verwertbar und macbar ist.

Für alle die es interessiert : Es werden Ströme und Spannungen
unter bestimmten Bedingungen gemessen (Elektrochemie, Potentiostaten)
Das Ganze findet eventuell auch noch auf mehreren Kanälen statt
und soll per serieller Schnittstelle (ev. Netzwertk) an einen
PC gekopplet werden.

Furtbichler 28. Okt 2013 18:52

AW: Aktualisierung und SendMessage
 
Zitat:

Zitat von jaenicke (Beitrag 1233365)
Ob der Overhead der Messagebehandlung da wirklich so viel geringer ist?
...Messages sind jedenfalls gerade bei größerem Datenaufkommen ungeeignet

Kann ich nicht bestätigen. Bei einer Implementierung eines Loggers wurden auch mehrere Tausend Messages pro Sekunde nicht langsamer abgearbeitet als per Thread. Der Bottleneck war hier eindeutig die Darstellung (wie immer).


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:22 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