![]() |
Threads hier sinnvoll?
Hallo
ich habe ein Programm geschrieben, dass aus mehreren Termen mehrer Geraden / Parablen / sonstiges zeichnet. Dabei kann der User beliebig viel Terme. Die Terme werden nacheinandere ausgerechnet und auch gleich gezeichnet. Bei Zeichnen wiederumm werden erst die Zahlen von 0 abwärts und dann die von 0 aufwärst bearbeitet. Nun mein Problem: Das Programm ist seeeeeehr langsam. Jetzt habe ich mich gefragt, ob mit hier Threads etwas bringen würde, zum Beispiel, die positive und die negative Berechung trennen oder jeder Term. Danke TO |
Hallo,
ich denke Threads bringen bei deinem Problem nicht sonderlich viel. Nur wenn das Programm bei der Berechnung hängt, würde ich sie in einen Thread auslagern. Ich würde das Programm beschleunigen, indem ich bei Parabeln z.B nur eine gewisse Anzahl an Punkten berechnen würde. Mfg Salomon |
Moin The Omega,
wie werden denn Die Terme übergeben? Wenn Du dazu Strings verwendest, kann das schon massiv auf die Geschwindigkeit gehen, wenn man die normalen Delphi Möglichkeiten benutzt. Welchen Datentyp verwendest Du denn für die eigentlichen Berechnungen? Werden viele eigene Funktionen benutzt? |
oki, ich poste hier mal den haupteil meines codes: (Erklärung der Veriablen weiter unten)
Code:
also hier die Erklärungen:
procedure geradezeichnen(term:string; index: integer; farbe: TColor;
canvas: Tcanvas;stringgrid:TStringgrid;gauge: TGauge); var i,counter: integer; wert: extended; wertalt: extended; temp:integer; begin; canvas.Pen.color := farbe; StringGrid.Cells[index,0] := term; counter := 0; x:=0; wert := termtoreal(term); if (von < 0) then temp := von*divi*-1 else temp := von*divi; //Negativ for i:= 1 downto (von*divi) do begin; //Berechnen des Wertes x:=(i-1)/divi; wertalt := termtoreal(term); //Fertig //Eintragen und zeichnen des Wertes if nodraw = false then begin; canvas.MoveTo(ileft+round((i*multi)/divi),itop-round(wert*multi)); canvas.lineTo(ileft+round(((i-1)*multi)/divi),itop-round(wertalt*multi)); end; //StringGrid.Cells[0,temp - counter +2] := floattostr(i/divi); StringGrid.Cells[index,temp - counter +2] := floattostr(wert); //Fertig wert := wertalt; gauge.Progress := gauge.Progress+1; inc(counter); if pm then application.ProcessMessages; end; end; counter := temp+2; x:=0; wertalt := termtoreal(term); //Positiv for i:= 0 to bis*divi do begin; //Berechnen des Wertes x:=i/divi; wert := termtoreal(term); //Fertig //Eintragen und zeichnen des Wertes if nodraw = false then begin; canvas.MoveTo(ileft+round((i*multi)/divi),itop-round(wert*multi)); canvas.lineTo(ileft+round(((i-1)*multi)/divi),itop-round(wertalt*multi)); end; //StringGrid.Cells[0,counter-1] := floattostr(i/divi); StringGrid.Cells[index,counter-1] := floattostr(wert); //Fertig wertalt := wert; gauge.Progress := gauge.Progress+1; inc(counter); if pm then application.ProcessMessages; end; end; end; term: der Term, z.b. "2x+4" index: irrelevant (zum Eintragen in ein Stringgrid) farbe: Linien Farbe divi: der Divisor, gibt an, auf wieviele Teile genau gerrechnet werden soll. Ist der divi zum Beispiel 1000 so wird jedes Tausendesl ausgerechnet un gezeichnet. von: Zahlenbereich von bis: Zahlenbereich bis nodraw: soll gezeichnet werden? ileft: x Koordinaten des Mittelpunkts (0|0) multi: Zoom, Multi von 2 vergrößert das Bild um das Doppelte itop: y Koordianten des Mittelpunkts (0|0) wert: ausgerechneter Wert wertalt: letzter berechneter Wert (zwecks Linienzeichnung) counter: irrelevant (zum Eintragen in ein Stringgrid) |
Ich habe mir jetzt Deinen Code nicht angeschaut :oops: es ist einfach zu spät.
Aber mla kurz zu Threads. Generell bringen Thread eigentlich nur ein zwei Situationen einen Vorteil. 1. Das Programm "friert" ein, während aufwendiger Berechnungen. 2. Das Programm läuft auf einem Mehrprozessorsystem. Auf einem Einprozessorsystem wird der Programmablauf auf jeden Fall langsamer, aber eine "nicht eingefrorene" Applikation mag dieses rechtfertigen. Je mehr Threads, destso größer der Overhead, welcher vom OS aufgebracht werden muss, um diese zu verwalten. |
Moin The Omega,
ich hab' mir das mal angeschaut, und mir sind da ein paar Dinge aufgefallen. Erst einmal zum Geschwindigkeitsproblem: TermToReal wird in einer Schleife aufgerufen, und verarbeitet den String term. String Ver- bzw. Bearbeitung kann ziemlich zeitaufwändig sein. Deshalb ist es durchaus möglich, dass TermToReal eine Bremse ist. Desweiteren, was hier nicht zu erkennen ist, könnte es von Vorteil sein den Parameter in TermToReal als const zu deklarieren (wenn möglich). Was mich noch interessieren würde: Funktioniert das so? Als ich versucht habe den Code zu strukturieren, damit ich ihn besser lesen kann, fiel mir auf, dass die Procedure eigentlich vor der Zeile counter := temp+2; endet. Diese und der Rest werden nicht mehr verarbeitet. Als ich mal versucht habe das Ganze zu compilieren, war der Compiler der gleichen Ansicht ;-) Meldung: Deklaration erwartet, aber Bezeichner 'counter' gefunden. BTW: Warum machst Du eigentlich hinter jedem Begin ein ; ? Was übrigens den Code noch leichter lesbar machen würde, wären Präfixe bei den Variablen, den Typ angeben, z.B. i für Integer, e für Extended oder auch s für String. |
warum der Code nicht läuft hat diesen Grund: ich habe ein Paar Zeilen rausgeschmissen, mit Funktionen, die noch nicht funktionieren oder die hier nicht relevant sind, vermutlich ist halt noch ein end zuviel oder zuwenig drine.
Der Code läuft ja, nur halt langsam. Aber evtl. habt ihr recht und es liegt an meiner TermtoReal funktion. Hier mal die gesamte Funktion:
Code:
der Code stammt alleridngs nicht von mir, sondern aus dem INet, wer einen besseren hat, nur her damit!
function pos0(c:char;s:string):integer;
//pos0 findet das Zeichen "+","-" ... nicht innerhalb von Klammern var k,z:integer; //z:=Anzahl der Klammern begin z:=0; for k:=1 to length(s) do Begin if s[k]='(' then inc(z); if s[k]=')' then dec(z); if (z=0) and (s[k]=c) then BEgin result:=k; //Treffer exit; ENd; End; result:=0; //nichts gefunden end; function anfang(s:string;c:char):string; begin anfang:=copy(s,1,pos0(c,s)-1); end; function copyab(const s:string; const i:integer):string; begin result:=copy(s,i,length(s)-i+1) end; function ende(s:string; c:char):string; begin ende:=copyab(s,pos0(c,s)+1) end; function hoch(x,y:real):real; begin result:=Power(x,y); //=e = (e ) =x end; function Wurzel(Value, WurzelNum: Extended): Extended; begin try Result := Power(Value, 1 / WurzelNum) except result := 0; end; end; function sinus( aWinkel : extended ) : extended; begin Result:= sin( DegToRad(aWinkel) ); end; function cosinus( aWinkel : extended ) : extended; begin Result:= cos( DegToRad(aWinkel) ); end; function tangens( aWinkel : extended ) : extended; begin Result:= tan( DegToRad(aWinkel) ); end; function TermToReal(s:string):real; // {Bisher '+' '-' '*' '/' Klammern und 'x' integriert, // d.h. gebrochen rationale Funktionen werden ausgewertet begin //showmessage(s); Empfehlenswert zum Verständnis if pos0('+',s)>0 then result:=TermToReal(anfang(s,'+'))+TermToReal(ende(s,'+')) else if pos0('-',s)>0 then result:=TermToReal(anfang(s,'-'))-TermToReal(ende(s,'-')) else if pos0('*',s)>0 then result:=TermToReal(anfang(s,'*'))*TermToReal(ende(s,'*')) else if pos0('/',s)>0 then result:=TermToReal(anfang(s,'/'))/TermToReal(ende(s,'/')) else if pos0('^',s)>0 then result:=hoch(TermToReal(anfang(s,'^')),TermToReal(ende(s,'^'))) else if pos0('$',s)>0 then result:=wurzel(TermToReal(anfang(s,'$')),TermToReal(ende(s,'$'))) else if pos0('s',s)>0 then result:=sinus(TermToReal(ende(s,'s'))) else if pos0('c',s)>0 then result:=cosinus(TermToReal(ende(s,'c'))) else if pos0('t',s)>0 then result:=tangens(TermToReal(ende(s,'t'))) else if (s>'') and (s[1]='(') then Begin //Am Anfang und Ende eine Klammer s:=copy(s,2,length(s)-2); result:=TermToReal(s) End else if s='x' then result:=x else //oder TermToReal(Form1.Ex.text) result:=StrToFloat(s); end; Dieser hier hat eh mehrer Fehler. So erkennt er z.b. "2x" nicht und auch ein Minus am Anfang führt zum Abbruch! |
Moin The Omega,
Probiers mal hiermit.
Code:
Das müsste eigentlich spürbar schneller werden.
[color=#000080]// Grob getestet 70% der Laufzeit der original Pos0[/color]
[b]function[/b] pos0([b]const[/b] c:char;[b]const[/b] s:[b]string[/b]):integer; [color=#000080]//pos0 findet das Zeichen "+","-" ... nicht innerhalb von Klammern[/color] [b]var[/b] k,z:integer; [color=#000080]//z:=Anzahl der Klammern[/color] [b]begin[/b] z := 0; [b]for[/b] k:=1 [b]to[/b] length(s) [b]do[/b] [b]begin[/b] [b]if[/b] s[k]='(' [b]then[/b] [b]begin[/b] inc(z); continue; [b]end[/b]; [b]if[/b] s[k]=')' [b]then[/b] [b]begin[/b] dec(z); continue; [b]end[/b]; [b]if[/b] (z=0) [b]and[/b] (s[k]=c) [b]then[/b] [b]begin[/b] result:=k; exit; [b]end[/b]; [b]end[/b]; Result := 0; [b]end[/b]; [b]function[/b] copyab([b]const[/b] s:[b]string[/b]; [b]const[/b] i:integer):[b]string[/b]; [b]begin[/b] Result:=copy(s,i,length(s)-i+1) [b]end[/b]; [b]function[/b] TermToReal(s:[b]string[/b]):real; [color=#000080]// {Bisher '+' '-' '*' '/' Klammern und 'x' integriert,[/color] [color=#000080]// d.h. gebrochen rationale Funktionen werden ausgewertet[/color] [b]begin[/b] [color=#000080]//showmessage(s); Empfehlenswert zum Verständnis[/color] [b]if[/b] pos0('+',s)>0 [b]then[/b] result:=TermToReal(copy(s,1,pos0('+',s)-1))+TermToReal(copyab(s,pos0('+',s)+1)) [b]else[/b] [b]if[/b] pos0('-',s)>0 [b]then[/b] result:=TermToReal(copy(s,1,pos0('-',s)-1))-TermToReal(copyab(s,pos0('-',s)+1)) [b]else[/b] [b]if[/b] pos0('*',s)>0 [b]then[/b] result:=TermToReal(copy(s,1,pos0('*',s)-1))*TermToReal(copyab(s,pos0('*',s)+1)) [b]else[/b] [b]if[/b] pos0('/',s)>0 [b]then[/b] result:=TermToReal(copy(s,1,pos0('/',s)-1))/TermToReal(copyab(s,pos0('/',s)+1)) [b]else[/b] [b]if[/b] pos0('^',s)>0 [b]then[/b] result:=Power(TermToReal(copy(s,1,pos0('^',s)-1)),TermToReal(copyab(s,pos0('^',s)+1))) [b]else[/b] [b]if[/b] pos0('$',s)>0 [b]then[/b] [b]begin[/b] [b]try[/b] result:=Power(TermToReal(copy(s,1,pos0('$',s)-1)),1/TermToReal(copyab(s,pos0('$',s)+1))); [b]except[/b] Result := 0; [b]end[/b]; [b]end[/b] [b]else[/b] [b]if[/b] pos0('s',s)>0 [b]then[/b] result:=sin(DegToRad(TermToReal(copyab(s,pos0('s',s)+1)))) [b]else[/b] [b]if[/b] pos0('c',s)>0 [b]then[/b] result:=cos(DegToRad(TermToReal(copyab(s,pos0('c',s)+1)))) [b]else[/b] [b]if[/b] pos0('t',s)>0 [b]then[/b] result:=tan(DegToRad(TermToReal(copyab(s,pos0('t',s)+1)))) [b]else[/b] [b]if[/b] (s>'') [b]and[/b] (s[1]='(') [b]then[/b] [b]Begin[/b] [color=#000080]//Am Anfang und Ende eine Klammer[/color] s:=copy(s,2,length(s)-2); result:=TermToReal(s) [b]End[/b] [b]else[/b] [b]if[/b] s='x' [b]then[/b] result:=x [b]else[/b] [color=#000080]//oder TermToReal(Form1.Ex.text)[/color] result:=StrToFloat(s); [b]end[/b]; Ich hab' einige Funktionsaufrufe direkt in TermToReal übernommen (linearisiert), dadurch fallen die hier jetzt nicht mehr enthaltenen Funktionen weg, ausserdem hab' ich noch Pos0 ein wenig überarbeitet. Die Funktion CopyAb macht allerdings Sinn, da hierdurch ein zweimaliger Aufruf von Pos0 entfällt, der wohl deutlich langsamer wäre. Es würde mich mal interessieren, ob's jetzt tatsächlich Veränderungen bringt. Eventuell könnte man noch mehr rausholen, wenn man nach jeder Zuweisung an Result in TermToReal direkt ein exit einbaut, auch wenn's das ganze unübersichtlicher macht. |
sorry Christian, aber die Zeiten sind haargenau gleich geblieben, beides mal 35 Sekunden (mein Programm mißt die Zeit!) Aber netter Nebeneffekt: die EXE wird kleiner (2 kb)
|
Für meine Verhältnisse rufst du pos0 zu oft auf. Probiere es mal mit der von mir veränderten TermToReal-Version:
Code:
[b]function[/b] pos0Ex([b]const[/b] c: Char; [b]const[/b] s: [b]string[/b]; out ResultValue: Integer): Integer;
[b]begin[/b] Result := pos0(c, s); ResultValue := Result; [b]end[/b]; [b]function[/b] TermToReal(s:[b]string[/b]):real; [i]// {Bisher '+' '-' '*' '/' Klammern und 'x' integriert, // d.h. gebrochen rationale Funktionen werden ausgewertet[/i] [b]var[/b] ps: Integer; [b]begin[/b] [i]//showmessage(s); Empfehlenswert zum Verständnis[/i] [b]if[/b] pos0Ex('+',s,ps)>0 [b]then[/b] result:=TermToReal(copy(s,1,ps-1))+TermToReal(copyab(s,ps+1)) [b]else[/b] [b]if[/b] pos0Ex('-',s,ps)>0 [b]then[/b] result:=TermToReal(copy(s,1,ps-1))-TermToReal(copyab(s,ps+1)) [b]else[/b] [b]if[/b] pos0Ex('*',s,ps)>0 [b]then[/b] result:=TermToReal(copy(s,1,ps-1))*TermToReal(copyab(s,ps+1)) [b]else[/b] [b]if[/b] pos0Ex('/',s,ps)>0 [b]then[/b] result:=TermToReal(copy(s,1,ps-1))/TermToReal(copyab(s,ps+1)) [b]else[/b] [b]if[/b] pos0Ex('^',s,ps)>0 [b]then[/b] result:=Power(TermToReal(copy(s,1,ps-1)),TermToReal(copyab(s,ps+1))) [b]else[/b] [b]if[/b] pos0Ex('$',s,ps)>0 [b]then[/b] [b]begin[/b] [b]try[/b] result:=Power(TermToReal(copy(s,1,ps-1)),1/TermToReal(copyab(s,ps+1))); [b]except[/b] Result := 0; [b]end[/b]; [b]end[/b] [b]else[/b] [b]if[/b] pos0Ex('s',s,ps)>0 [b]then[/b] result:=sin(DegToRad(TermToReal(copyab(s,ps+1)))) [b]else[/b] [b]if[/b] pos0Ex('c',s,ps)>0 [b]then[/b] result:=cos(DegToRad(TermToReal(copyab(s,ps+1)))) [b]else[/b] [b]if[/b] pos0Ex('t',s,ps)>0 [b]then[/b] result:=tan(DegToRad(TermToReal(copyab(s,ps+1)))) [b]else[/b] [b]if[/b] (s<>'') [b]and[/b] (s[1]='(') [b]then[/b] [b]begin[/b] [i]//Am Anfang und Ende eine Klammer[/i] s:=copy(s,2,length(s)-2); result:=TermToReal(s) [b]end[/b] [b]else[/b] [b]if[/b] s='x' [b]then[/b] result:=x [b]else[/b] [i]//oder TermToReal(Form1.Ex.text)[/i] result:=StrToFloat(s); [b]end[/b]; |
Sorry, aber auch deine Möglichkeit bringt keinen Zeitgewinn!
|
Der Geschwindigkeitsgewinn ist bei wenigen Durchläufen minimal. Bei meinem Test '10+20*10-x^2*234,5+(10+20)*30' mit 10000 Durchläufen waren es ca. 50 ms Gewinn;
Ändere mal meine pos0Ex Funktion in folgende um. Danach hatte ich einen Gewinn zu deiner Version von ca. 200 ms.
Code:
[b]function[/b] pos0Ex([b]const[/b] c: Char; [b]const[/b] s: [b]string[/b]; out ResultValue: Integer): Integer;
[i]//pos0Ex findet das Zeichen "+","-" ... nicht innerhalb von Klammern[/i] [b]var[/b] k, z: Integer; [i]//z:=Anzahl der Klammern[/i] [b]begin[/b] z := 0; [b]for[/b] k := 1 [b]to[/b] Length(s) [b]do[/b] [b]begin[/b] [b]case[/b] s[k] [b]of[/b] '(': Inc(z); ')': Dec(z); [b]else[/b] [b]if[/b] (z = 0) [b]and[/b] (s[k] = c) [b]then[/b] [b]begin[/b] Result := k; [i]//Treffer[/i] ResultValue := k; Exit; [b]end[/b]; [b]end[/b]; [b]end[/b]; ResultValue := 0; Result := 0; [b]end[/b]; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:48 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