AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

MemoryLeaks mit s := I.ToString

Ein Thema von Kraisel · begonnen am 7. Nov 2014 · letzter Beitrag vom 12. Nov 2014
Antwort Antwort
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.542 Beiträge
 
Delphi 12 Athens
 
#1

AW: MemoryLeaks mit s := I.ToString

  Alt 8. Nov 2014, 10:35
Mehrere in Fibern ausgeführte Prozeduren müssten doch langsamer sein, als einfach mehrere Prozeduren in einem Thread nacheinander aufzurufen?

Der einzige Vorteil, den ich da seh, daß man den Fiber einfach mal so mittendrin anhalten könnte, aber einen Thread kann man ja genauso gut anhalten. (auch wenn man das eigentlich nicht machen sollte, was dabei allerdings auch für die Fiber gilt)

Nachteil, man zerschießt sich die automatische Speicherverwaltung.
Das fängt im Delphi schon bei den Strings, dyn. Arrays, Interfaces und Variants an, und geht im NextGen bei allen Objekten weiter. (hatte hier gestern gelesen, daß man versucht Fiber auch in anderen Platformen haben will)



Die winzige Lösung, welche ich sehe, daß sich Fiber nicht einfach so selber beenden dürfen.
Man könnte die aufgerufenen Prozeduren in eine leere Dummy-Procedure legen, wo nur der Aufruf der Funktion drin ist und sonst nichts, was irgendwie Speicher oder die Exceptionbehandlung beinhalten sollte (außer eventuell genau an Fiber angepasste Funktionen). Also genauso wie beim TThread.Execute.



PS: Sobald auch nur eine lokale String-Variable in einer Funktion deklariert wurde, egal ob manuell oder durch soeine interne Variable, wird auch noch ein Try-Finally dort eingebaut.

Dieser Code
Delphi-Quellcode:
procedure Test;
var
  s1,s2: String;
  i: Integer;
begin
  i := 123;
  s1 := IntToStr(I);
  GetDynVarPrms(s1);
  s2 := I.ToString;
  GetDynVarPrms(s2);
end;
wird, so in etwa, in Folgendes übersetzt (grob in Pure-Pascal übersetzt)
Delphi-Quellcode:
procedure Test;
var
  intern : record
    s1, s2, intern_s3: String;
    i: Integer;
  end;
begin
  {$REGION 'begin'}
  PushVariablesToStack(intern); // inkl. Initialize(intern); , indem die String-Variablen mit 0 beschrieben werden
  try
    with intern do begin
  {$ENDREGION}
      i := 123;
      IntToStr(I, s1); // procedure IntToStr(i: Integer; var Result: string);
      GetDynVarPrms(s1);
      TIntegerHelper.ToString(i, intern_s3); //intern_s3 := I.ToString; // procedure TIntegerHelper.ToString(Value: Integer; var Result: string); inline;
      UStrLAsg(s2, intern_s3); //s2 := intern_s3;
      GetDynVarPrms(s2);
      // und hier hat dein Fiber alles weggeknallt
  {$REGION 'end'}
    end;
  finally
    Finalize(intern);
  end;
  PopVariablesFromStack(intern);
  {$ENDREGION}
end;
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 8. Nov 2014 um 10:54 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Kraisel
Kraisel

Registriert seit: 19. Mär 2012
Ort: Bochum-Linden
64 Beiträge
 
Delphi 12 Athens
 
#2

AW: MemoryLeaks mit s := I.ToString

  Alt 8. Nov 2014, 18:57
VORSICHT: Wenn die Fiberumschaltung irgendwo in einer aufgerufenen Methode vor dem finally geschieht, und der Fiber dann beendet wird, wird finally niemals aufgerufen. Dieses Problem hat man auch beim Thread, wenn er mit Suspend angehalten und dann verworfen wird.

Allgemein: Die erste Entscheidung bei paralleler Programmierung ist, ob man dadurch einen Performancegewinn oder deutlich besser trennbaren Code haben will. Beides ist leider nur selten möglich.

Ob Threads, Fiber oder einfach parallele Abläufe durch geschicktes orthogonales Coding muss sorgfältig abgewägt werden.

Threads machen z.B. Sinn, wenn durch den Einsatz mehrere CPUs echte Parallelität gewährleistet wird, z.B beim Suchen eines Elementes in einer unsortierten riesigen Liste. Einfach nur mehrere Threads aufmachen reicht aber auch da nicht. Das Betriebssystem könnte nämlich mehrere oder sogar alle Threads in einer CPU laufen lassen. Dann wirds sogar deutlich langsamer als eine Iteration über alle Elemente in einem Thread. Die Umschaltung eines Threads ist nicht deterministisch und kostet inkl. der internen völlig intransparenten Optimierung des Betriebssystems 1..100µs. Bei Threads vergisst man gerne, dass das Betriebssystem jeden Thread nicht nur umschaltet, sondern dass die CPU-Ressourcen für die verdeckte interne Optimierung mit steigender Anzahl überproportional ansteigt. Und selbst ein Assemblerbefehl wie ein normales Increment einer Speicherstelle MUSS synchronisiert werden, wenn auch andere Threads darauf zugreifen können. Es gibt aber vier intrinsische Atomic-Assemblerbefehle, die auch in Delphi zur Verfügung stehen.

Fazit: Mehr Threads als CPUs machen NUR für besser trennbaren Code Sinn. Die Performance wird nämlich je zusätzlichem Thread (mehr als CPUs) zwangsläufig immer schlechter. Das ist leider, bis auf ganz wenig Ausnahmen, allgemeingültig. Wenn möglich, ist klassisches Pollen eben fast immer wesentlich schneller als komplexe Strukturen.

Und genau da werden Fiber spannend. Die machen nämlich Sinn, wenn die Laufzeit des Codes bis zur nächsten notwendigen Umschaltung kurz ist, und man davon viele (gerne auch mehrere 1.000) hat. Die Umschaltung eines Fiber ist mit unter 50ns ca. 20..2.000 mal schneller als beim Thread. Wenn man also viele Objekte oder Methoden hat, die alle parallel etwas tun müssen, und man auch keine Verriegelung untereinander im Code haben darf oder nicht möchte, dann machen Fiber absolut Sinn. Threads wären da viel zu langsam, viel zu aufwändig und auch viel zu fehleranfällig.

Eigenes geschicktes Coding ist die schnellste Variante, birgt aber den Nachteil, diese Tools, die man dafür benötigt, immer zu pflegen, und an die neuen Compiler anzupassen. Und da kein Dispatcher (Stackumschaltung) vorhanden ist, sieht der Code zwangsweise an manchen Stellen einfach etwas unübersichtlich aus. Diese Variante habe ich erfolgreich seit über 10 Jahren weltweit in vielen Anlagen (365x24) im Einsatz. Da diese Projekte aber immer komplexer werden, möchte ich nun besser lesbaren und wartbaren Code in den parallelen Prozessen haben. Das sind im Moment meine Entscheidungsprobleme.
Peter Kaisler
Das einzig Komplizierte ist zu begreifen wie einfach es ist.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.542 Beiträge
 
Delphi 12 Athens
 
#3

AW: MemoryLeaks mit s := I.ToString

  Alt 8. Nov 2014, 20:59
Dieses Problem hat man auch beim Thread, wenn er mit Suspend angehalten und dann verworfen wird.
Dieses Problem gibt es nicht, da man Threads niemals von außen anhält.
Man sagt einenm Thread er solle sich bitte anhalten und er macht das dan selber, an definierter/sicherer Stelle.

Das Problem liegt nicht nur beim Beenden, sondern auch beim ausführenden Code.
Beispiel: Du hälst den an, während er grade Speicher reserviert/freigibt, oder auf irgendeine Resource zugreift ... wenn der Thread dabei etwas lockt, dann wird das nie wieder entsperrt und kann womöglich auch andere Dinge blockieren, wie z.B. alles was im selben Speicherblock liegt und das dann nie wieder freigegeben werden kann.
Schlimmer noch, wenn du versuchst das freizugeben, landet man entweder in einem Deadlock oder es gibt zumindestens eine Exception (falls der Zugriff über ein Timeout verfügt.


Genauso das beenden eines Threads ... sowas hat der Thread gefälligst selber zu machen.
Alles andere sind maximal notfallmaßnahmen, bei welchen man damit rechnen muß, daß irgendwas kaputt geht.

Das ist genauso, also wenn man zum PC-Runterfahren den Stecker zieht.


Nicht umsonst gibt der Compiler nun endlich eine Warnmeldung aus, wenn man Suspend verwendet.
Delphi-Quellcode:
// This function is not intended to be used for thread synchronization.
procedure Suspend; deprecated;
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 8. Nov 2014 um 21:08 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Kraisel
Kraisel

Registriert seit: 19. Mär 2012
Ort: Bochum-Linden
64 Beiträge
 
Delphi 12 Athens
 
#4

AW: MemoryLeaks mit s := I.ToString

  Alt 8. Nov 2014, 21:58
Für den Thread hast Du völlig recht. Da habe ich mich vielleicht nicht klar genug ausgedrückt, denn ich wollte sicher nicht anregen, dass man Suspend benutzen soll. Ich habe lediglich versucht, die Analogie zum Fiber hergestellt, denn da besteht leider immer das Problem, dass das Ende der Methoden in denen umgeschaltet wird niemals aufgerufen werden, wenn der Fiber gerade beendet wird. Er kann sich leider auch nicht selber beenden. Wenn er das tut, indem er einfach die Methode verlässt, wird der Thread, indem er läuft, beendet, und alle anderen Fiber stehen unkontrolliert in ihrer letzten Umschaltung. Und das ist wohl der großer Nachteil bei Fiber. Man muss alle Spielregeln beachten und genau wissen, was man da darf und was nicht. Wenn man das ignoriert, müllt man sich langfristig den Speicher zu. Ansonsten sind Fiber aber eben wesentlich schneller als Threads. Man kann leider nicht alles haben.

Vielen Dank für alle Hinweise.
Peter Kaisler
Das einzig Komplizierte ist zu begreifen wie einfach es ist.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.542 Beiträge
 
Delphi 12 Athens
 
#5

AW: MemoryLeaks mit s := I.ToString

  Alt 9. Nov 2014, 10:19
OK, der Thread des Fiber darf nicht vom Fiber beendet werden, aber auch der Fiber muß sich selber beenden, indem er selber am Ende eine bestimmte Funktion aufruft.
Von außen darf auch ein Fiber nicht einfach so unkontrolliert angehalten/beendet werden, damit er nicht in einem "ungünstigen" Zustand stehen bleibt.

Egal ob Thread oder Fiber, sobald etwas globales verwendet wird, muß man aufpassen, daß dieses im Moment des Anhaltens nicht benutzt wird,
außer es gibt atomare Locking-/Zugriffsfunktionen und man könnte die Locks von außen freigeben.
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 9. Nov 2014 um 10:23 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#6

AW: MemoryLeaks mit s := I.ToString

  Alt 9. Nov 2014, 11:29
Ich hab irgendwie den Eindruck, ihr wisst beide worum es geht und was man Grundsätzlich beachten muss, und redet jetzt nur noch ein bisschen aneinander vorbei. Für Leute ohne Erfahrung mit Nebenläufigkeit ist das sicher interessant, aber ansonsten nicht sonderlich produktiv
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#7

AW: MemoryLeaks mit s := I.ToString

  Alt 10. Nov 2014, 00:31
Hey, lass uns doch auch mal den Coolen raushängen. Und auch das Nebeneinadervorbeireden birgt ja noch zusätzliches Wissen. Den Beitrag über die Vor- und Nachteile und wann was besser geeignet ist, fand ich interessant.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:11 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