![]() |
warum verlangsamen diese beiden Funktionen meinen Thread?
Hallo und guten Tag an alle DP´ler
Mal wieder eine kleine Verständnisfrage. Und zwar werden einige Änderungen am ComPorts überwacht und sollen auf einer Form dargestellt werden. Dies funktioniert zumindest auch, allerdings verlangsamt dies mein Programm erheblich und blockiert es zumindest für 2-3 Sekunden (z.B. bei einem Klick auf der Form ändert sich das Checked einer Checkbox nicht sofort. Hier mal alle relevanten Funktionen. Die Refresh der Formen (welche ich denke, dass sie mich am meisten behindern, hab ich schon versucht mit hilfe von boolschen Variablen deutlich zu verringern):
Delphi-Quellcode:
Also der Fehler sollte immer meiner Meinung nach immer noch daran liegen, dass er zuviel macht, sehe aber gerade nicht, wo ich die Interaktion zwischen Thread und Formen noch NICHT eingeschränkt habe, wenn keine Änderung vorliegt.
procedure TControlCardControlThread.Execute;
var c, iIndex: integer; begin for iIndex := 1 to 5 do (Form3.findcomponent('CheckBox' + inttostr(iIndex+8)) as TCheckBox).Checked:= fabDigChannelSignals[iIndex]; repeat c := GetTickCount; Synchronize(UpdateForm3); c := {interval}50 - (GetTickCount - c); if c > 0 then Sleep(c); until Terminated; if assigned(FsLComport) then FsLComport.Free; end; {////////////////////////////////////////////////////////////////////////////////////} {/ Interaktion mit Oberfläche /} {////////////////////////////////////////////////////////////////////////////////////} // bei dieser Form sollte festgestellt werden, ob sich irgendwas verändert hat und // nur bei vorhandenen Änderungen sollte auch Refreshed werden. Ständiges neuzeichnen // führt zum ausbremsen des TThreads! procedure TControlCardControlThread.UpdateForm3; var i: integer; bGeneralDigChannelInput, bCriticalDigChannelInput, bUpdateDataForm1, bUpdateDataForm3: boolean; begin bUpdateDataForm1 := ComportSearch(FsLComport); bUpdateDataForm3 := false; bgeneralDigChannelInput := false; bcriticalDigChannelInput := false; for i := 1 to 5 do begin case not(FabDigChannelSignals[i] xor Board.digEingang[i]) of false: begin bUpdateDataForm3 := true; DoSingleDigChannelInput(i); bGeneralDigChannelInput := true; if i in [2..4] then bcriticalDigChannelInput := true; FabDigChannelSignals[i] := Board.digEingang[i]; (Form3.findcomponent('CheckBox' + inttostr(i+8)) as TCheckBox).Checked:= fabDigChannelSignals[i]; end; end; if (i in [1..2]) and ((Form3.findcomponent('ProgressBar' + inttostr(i)) as TProgressBar).Position <> Board.anaEingang[i]) then begin (Form3.findcomponent('ProgressBar' + inttostr(i)) as TProgressBar).Position := Board.anaEingang[i]; bUpdateDataForm3 := true; end; end; if bUpdateDataForm3 then Form3.Refresh; // <-- Änderung nur refresh, wenn Änderung vorhanden sind if FbBlinkRedLight then Board.RedLight := not Board.RedLight; if bGeneralDigChannelInput then doGeneralDigChannelInput; if bCriticalDigChannelInput then doCriticalDigChannelInput; // Hier ebenso Änderungen überprüfen und nur bei vorhandenen Änderungen das neuzeichnen // auslösen! if bUpdateDataForm1 then begin Form1.Memo1.Clear; Form1.Memo1.Lines := FsLComport; Form1.Refresh; end; case Counter of 0: Form3.StatusBar1.Panels[0].Text := '/'; 1: Form3.StatusBar1.Panels[0].Text := '|'; 2: Form3.StatusBar1.Panels[0].Text := '\'; 3: Form3.StatusBar1.Panels[0].Text := '-'; end; Counter := Counter + 1; if Counter > 3 then Counter := 0; end; {////////////////////////////////////////////////////////////////////////////////////} {/ Überwachungsfunktion /} {////////////////////////////////////////////////////////////////////////////////////} // In eine Funktion umarbeiten, die true zurückgibt, wenn keine Änderungen vorhanden sind // oder false wenn Änderungen vorhanden sind. function TControlCardControlThread.ComportSearch(var List: TStringList):boolean; var ComBuffer: TComport; TempLineArray: array of Integer; bLine: boolean; i, j: integer; begin ComBuffer := TComport.Create; result := false; try SetLength(TempLineArray,0); for i := 0 to ComBuffer.Anzahl - 1 do begin j := List.IndexOf(inttostr(ComBuffer.Comportnummer[i])); case j of -1: begin result := true; List.Add(inttostr(ComBuffer.Comportnummer[i])); // Eintrag ist noch nicht vorhanden -> Eintrag wird hinzugefügt SetLength(TempLineArray,Length(TempLineArray)+1); TempLineArray[Length(TempLineArray)-1] := List.IndexOf(inttostr(ComBuffer.Comportnummer[i])); end; else begin SetLength(TempLineArray,Length(TempLineArray)+1); TempLineArray[Length(TempLineArray)-1] := j; end; end; end; //in Temp Linearray sind jetzt alle Zeilen Nummern der StringList enthalten, die //auch in der Comport-Liste vorhanden sind. Nun müssen die überflüsigen Zeilen nur gelöscht werden for i := 0 to List.Count -1 do begin bLine := false; for j := 0 to Length(TempLineArray) do if i= TempLineArray[j] then bLine := true; // Zeile ist in TempLineArray vorhanden und soll somit NICHT gelöscht werden! if not bLine then begin List.Delete(i); //Wenn die Zeile nich in TEmpLineArray vorhanden ist, muss der Comport geschlossen worden sein und kann somit aus der Liste gelöscht werden. result := true; end; end; finally SetLength(TempLineArray,0); ComBuffer.Free; end; end; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Hier noch die Comport-Klasse: Type TComport = class private bPorts: boolean; FsLComports: TStringList; function ComPort(ComPortNummer: byte): longbool; function ComportScan: boolean; function GetComport(index: integer): integer; function GetAnzahl: integer; public constructor Create; reintroduce; destructor destroy; override; property verfuegbarePorts: boolean read bPorts; property Comportnummer[Index: integer]: integer read GetComport; property Anzahl: integer read GetAnzahl; end; Constructor TComport.Create; begin inherited create; FsLComports := TStringlist.Create; bPorts := ComportScan; end; destructor TComport.Destroy; begin FsLComports.Free; inherited destroy; end; function TComport.GetComport(index: Integer): integer; begin result := strtoint(FsLComports[Index]); end; function TComport.GetAnzahl; begin result := FsLComports.Count; end; // Funktion, die überprüfft, ob an der Comschnittstelle mit der Nummer "ComPortNummer" // ein Gerät angeschlossen ist (ob eine Kommunikation geöffnet ist) oder nicht. function TComport.ComPort(ComPortNummer: byte): longbool; var TestHandle : integer; begin TestHandle :=CreateFile(PChar('\\.\COM'+IntToStr(ComPortNummer)),GENERIC_READ or GENERIC_WRITE,0, nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,LongInt(0)); if (TestHandle <= 0) then Result := false else begin Result := true; CloseHandle(TestHandle); end; end; // Funktion, die alle ComPorts bis zu einer vom Programmierer festgelegten maximal // ComPortnummer anspricht. function TComport.ComportScan: boolean; var i: integer; aBuffer: array of Integer; begin for i := 0 to 20 do if ComPort(i) then FsLComports.Add(inttostr(i)); if FsLComports.Count = 0 then result := false else result := true; end; Hoffe ihr könnt mir wieder helfen BAMatze |
Re: warum verlangsamen diese beiden Funktionen meinen Thread
Also mit fällt nichts besonderes auf, darum nur ein paar Ideen:
- FindComponent kannst Du Dir sparen wenn Du eine eigene Liste(/Array) der relevanten Controls führst. - Der Thread sollte keine erhöhte Priorität haben, da er durch das Synchronize eh immer wieder ausgebremst wird und auf den Hauptthread wartet. Wenn der Hauptthread nicht dazu kommt Botschaften zu verarbeiten kann Synchronize ewig warten. - Reagiert der Thread schneller, wenn du mit der Maus auf dem Formular herumeierst? Dann hilft das Umbiegen von WakeMainThread (hatte ich ja schonmal vorgeschlagen). [EDIT] - Wieviel Zeit verbringt der Thread im Sleep? [/Edit] Grüsse, Dirk |
Re: warum verlangsamen diese beiden Funktionen meinen Thread
Hallo,
ich würde mal sagen dein Problem liegt hier:
Delphi-Quellcode:
So wie es aussieht, machst du die ganzen Prüfungen, ob ich etwas an den COM-Ports geändert hat, in der UpdateForm3. Diese Methode lässt du aber mit Synchronize aufrufen, was bewirkt, dass der Thread des Formulars solange angehalten wird, bis die Abarbeitung der UpdateForm3 abgeschlossen ist.
Synchronize(UpdateForm3);
Pack doch diese ganzen Checks in eine andere Methode oder einfach in die Execute Methode und schreib in die UpdateForm3 nur rein, was an der Form3 geändert werden soll. Und dann rufst du die UpdateForm3 mit Synchronize nur dann auf, wenn sich wirklich was geändert hat. So wie du es gerade implementiert hast, ist der Thread ziemlich nutzlos. Ich hoffe, dass ich es einiermaßen verständlich erklärt habe. [edit] Ok ich habe grad nochmal die Delphihilfe angeschaut und Synchronize bewirkt, dass die Methode im Hauptthread ausgeführt wird und der aktuelle Thread für die Zeit der Ausführung unterbrochen wird. Es kommt im Endeffekt aber auf das selbe raus, dass der Hauptthread während der Abarbeitung der UpdateForm3 nicht auf andere Sachen reagieren kann. [/edit] |
Re: warum verlangsamen diese beiden Funktionen meinen Thread
Ok werde ich mal versuchen umzusetzen. Danke euch
[Edit] Folgende kleine Änderung hat die Schnelligkeit des Threads wieder zu 100% hergestellt (orientiert an dem Lösungsvorschlag von hugo1990):
Delphi-Quellcode:
[/Edit]
// bUpdateDataForm1 ist jetzt eine private-Variable des TThreads
procedure TControlCardControlThread.Execute; var c, iIndex: integer; begin for iIndex := 1 to 5 do (Form3.findcomponent('CheckBox' + inttostr(iIndex+8)) as TCheckBox).Checked:= fabDigChannelSignals[iIndex]; repeat c := GetTickCount; bUpdateDataForm1 := ComportSearch(FsLComport); // <-- Zeile aus der UpdateForm3-Procedure entfernt und hier wieder eingefügt Synchronize(UpdateForm3); c := {interval}50 - (GetTickCount - c); if c > 0 then Sleep(c); until Terminated; if assigned(FsLComport) then FsLComport.Free; end; |
Re: warum verlangsamen diese beiden Funktionen meinen Thread
Verstehe aber auch nicht so ganz, warum du dir die vorhandenen Comports in einer Stringliste merkst.
Wäre da nicht ein Statischer Array von der Art Comportaktiv : Array [1..20] of boolean viel einfacher? |
Re: warum verlangsamen diese beiden Funktionen meinen Thread
Noch eine Anregung, um ein Performanceproblemen bei Verwendung von Synchronize zu umgehen: Verwende Windows-Messages, die das Formular veranlassen, die Threadinformationen neu zu zeichnen.
Dem Thread übergibst du das Handle des Formulars und ruft dann einfach im Thread 'PostMessage(HandleDerForm...)' auf. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:23 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