Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Threads hier sinnvoll? (https://www.delphipraxis.net/1097-threads-hier-sinnvoll.html)

theomega 17. Okt 2002 16:16


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

Salomon 17. Okt 2002 16:23

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

Christian Seehase 17. Okt 2002 18:02

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?

theomega 17. Okt 2002 18:50

oki, ich poste hier mal den haupteil meines codes: (Erklärung der Veriablen weiter unten)

Code:
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;
also hier die Erklärungen:
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)

sakura 17. Okt 2002 23:24

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.

Christian Seehase 18. Okt 2002 00:33

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.

theomega 18. Okt 2002 13:21

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:
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;
der Code stammt alleridngs nicht von mir, sondern aus dem INet, wer einen besseren hat, nur her damit!
Dieser hier hat eh mehrer Fehler. So erkennt er z.b. "2x" nicht und auch ein Minus am Anfang führt zum Abbruch!

Christian Seehase 18. Okt 2002 15:49

Moin The Omega,

Probiers mal hiermit.

Code:
[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];
Das müsste eigentlich spürbar schneller werden.

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.

theomega 18. Okt 2002 16:58

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)

jbg 18. Okt 2002 17:39

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];


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