06. september 2006 - 11:37Der er
6 kommentarer og 1 løsning
Overføre Tung GraphPlot i TTimer til TThread?
Hej Alle,
Jeg har lavet et program der opsamler nogen data fra en serial port og plotter dem i nogen grafer.
Indtil videre kører programmet således, at jeg har en TTimer der kører hver 100ms og så opdaterer grafen hvis der er nye data. Problemet er at når der kommer mange data, således at det tager flere sekunder om at opdatere plottet, så hakker mit program ubruligt meget (fx. har jeg en command line promt hvor man kan sende kommandoer den anden vej).
Kan man få programmet til at køre mere "smooth", hvis jeg nu fx plottede grafen i en thread? Eller burde jeg gå efter at sætte nogen af de andre funktioner, som programmet udfører, over i en thread (fx dataopsamlingen - tager ingen CPU tid, men bliver også påviket af de langsomme grafer).
>psycosoft-funware: Med "sådanne", mener du der GraphPlot funktionen, ikke? Det var også det jeg tænkte, men er der ikke nogen problemer med at have fælles data med resten af programmet - samt at opdatere en grafisk komponent fra en TThread?
Programmets funktioner (opdelt efter prioritet):
1. Opsamling af data fra seriel port. Lagring i Datastruktur (Dynamic Arrays) 2. GUI (Command line + Script editor + Manipulering (e.g. zoom) af grafer + valg af fremvisnings type) 3. Grafisk fremvisning af data fra Datastrukturen. a) Hentning af data til midlertidige variabler. b) Opsætning af TBitmap til at tegne på. (benytter en graf-komponent baseret på TPMATH) c) Tegning grafer udfra de midlertidige variabler d) Nedlukning af midlertidige variabler
Punkt 3c tager langt det meste af tiden, og jeg vil helst ikke have at det på virker punkt 1 og punkt 2.
Er ikke nogen ørn til objektorienteret Delphi - er selvlært med basis i assembler programmering fra C64 + Amiga.
Drop de dynamiske arrays. De er langsomme (og ineffektive her)! Data fra den serielle port skulle du proppe i en TQueue og så pop'e dem ud på en graf via en tråd der looper og sleep(0)'er på skift.
Der er lige noget mht. låsning af køen, men det kan laves meget simpelt ved at stoppe tråden fra at hente fra køen mens man propper i. En meget simpel mutex.
Det som du spørger om hjælp af er kun 1 og 3c, ikke? Hvad er det for midlertidige variable du skriver om?
Kan godt prøve at se på det i aften - ingen garanti.
>hrc Ved godt de dynamiske arrays måske ikke er verdens hurtigste, men det er nu ikke dem der er problemet her.... Tror måske du misforstår.. Det jeg måler er fx temperaturmålinger som funktion af tid... Jeg får en måling fra forskellige temperatur sensorer hver ca. 0.1 sekund. Disse skal lagres i hukommelsen, således at grafen kan vise så hvad temperaturen var i forskellige områder af apparatet som funktion af tid.
Hvis jeg brugte TQueue og pop'ede ville de gamle værdier vel forsvinde igen ?!?!
De midlertidige variabler benyttes til : 1) Ændre formatet af data til det som plot-rutinen forstår. 2) Sikre at der ikke plottes halv-færdige data, hvis der skulle opsamles nye data mens plottet opdaterer...
Jeg mener nu stadig godt at du kan bruge data fra dine loggere i en TQueue. Jeg har lavet nedenstående lille protram og det eneste "svære" punkt er, om min mutex-konstruktion er solid nok.
Prøv at kigge på det. Jeg mener i alt fald den er hurtigere end dine /&%#/!"% dynamiske lister.
function TTempLogQueue.Peek: TTempLogData; begin result := TTempLogData(inherited Peek); end;
function TTempLogQueue.Pop: TTempLogData; begin result := TTempLogData(inherited Pop); end;
procedure TTempLogQueue.Push(aTempLogData: TTempLogData); begin while fLocked do sleep(7); // Primtal for ikke at løbe ind i den anden sleeper hele tiden
procedure TPlotThread.Execute; begin inherited; while not Terminated do begin if fTempLogQueue.Count > 0 then begin while fTempLogQueue.Locked do sleep(3); // Primtal for ikke at løbe ind i den anden sleeper
if assigned(fTempLogData) then FreeAndNil(fTempLogData); // Skil os af med forbrugte data. end else sleep(0); end; end;
procedure TPlotThread.PlotValue; begin if fChart.Series[0].Count > 300 then fChart.Series[0].Delete(0); fChart.Series[0].AddXY(fTempLogData.fDateTime,fTempLogData.Value); end;
end.
I øvrigt bør du placere dine temporære variable i tråden så den kan for lov til at tygge på det. Intet må forstyrre din dataopsamler. Hvis du vil have en kopi af koden så kan du skrive til mig på hrc_public at hotmail.
Jeg har løst problemet ved kun at indsætte en Application.Processmessages i plotter-rutinen. Jeg kalder GraphPlot fra TTimer, som nu er sat til at køre hver 10ms. Programmet/Dataopsamling kører smooth selvom den skal plotte >100k punkter.
hrc får points for hjælpen.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.