Autor Beitrag
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Fr 04.09.09 20:27 
(Aus diesem Post entstanden)
TFiber

Die Klasse TFiber stellt eine separate Ausführungsumgebung zur Verfügung, die unabhängig von Threads existiert. Diese hat einen eigenen Satz von Registers, Stack, Exception Chain und Instruction Pointer.

Im Gegensatz zu einem Thread wird ein Fiber nicht vom Betriebsystem verwaltet und ausgeführt, sondern muss manuell in einem Thread der Wahl ausgeführt werden. Daher sieht das Starten eines Fibers erst mal aus wie ein normaler Funktionsaufruf. Der Vorteil ist aber, dass die Ausführung eines Fibers an einer beliebigen Stelle gestoppt und zu einem späteren Zeit forgesetzt werden kann. Ausserdem ist es möglich, mit einem einfachen Funktionsaufruf an beliebiger Stelle im Kontrollfluss ein Fiber von einem Thread auf einen anderen zu transferieren.

Anwendungsfälle
- Fibers können verwendet werden, um an beliebiger Stelle während der Ausführung den Thread zu wechseln, bspw. um den MainThread freizugeben.

- Fibers können verwendet werden, um CoRoutinen zu implementieren.

- Fibers können die Anzahl Threads reduzieren, wenn sehr viele Ausführungspfade existieren, diese aber nicht ständig laufen. So kann der Fiber inaktiv sein, bis wieder Arbeit ansteht, um dann wieder in einem Thread aus einem Threadpool ausgeführt zu werden.

Features
- Transparentes Exception Handling über Thread-Grenzen hinweg.
- "Inline" Wechsel zwischen MainThread und Worker-Thread aus einem ThreadPool
- Direkter Transfer von einem Fiber in einen anderen möglich

Methoden von TFiber
- SwitchToWorkerThread: Ausführung in einem WorkerThread fortführen
- SwitchToMainThread: Ausführung im MainThread fortführen
- Yield: Kontrolle an Thread zurückgeben
- Transition: Kontrolle an anderen Fiber übergeben
- Resume: Kontrolle von Thread an Fiber übergeben

Properties von TFiber
- FreeOnTerminate: Instanz automatisch freigeben, wenn der Ausführungspfad des Fibers abgeschlossen ist.

Die Units mit Beispielprojekt im Anhang oder hier. Falls jemand nach einer ThreadPool Implementierung sucht ist hier eine mit dabei.

Beispiel
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure TForm1.Button1Click(Sender: TObject);
begin

  // Rerun this method in a fiber
  if TEventFiber.RerunInFiber(Self, Button1Click) then
    Exit;

  try
    TFiber.Current.SwitchToWorkerThread;

    // Code here runs in a worker thread

  finally
    TFiber.Current.SwitchToMainThread;
  end;

  // Code here runs in the main thread again

end;


// Edit: Race condition fixed
Einloggen, um Attachments anzusehen!


Zuletzt bearbeitet von delfiphan am Fr 29.07.11 13:52, insgesamt 11-mal bearbeitet

Für diesen Beitrag haben gedankt: bummi, Hidden
delfiphan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Fr 02.04.10 16:42 
Die Library scheint niemand zu mögen ;) habe sie jetzt noch weiter vereinfacht.

Bei Events vom Typ TNotifyEvent muss man jetzt nur noch TEventFiber.RerunInFiber ausführen, um die Vorteile von Fibers nutzen zu können. Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure TForm1.Button1Click(Sender: TObject);
begin

  // Diese Methode in einem Fiber starten
  if TEventFiber.RerunInFiber(Self, Button1Click) then
    Exit;

  try
    // Schnell vom Mainthread in einen Workerthread wechseln
    TFiber.Current.SwitchToWorkerThread;

    // ...
    // hier eine Berechnung, die lange dauert (läuft in einem Thread)
    // ...

  finally
    // Und wieder zurück in den Mainthread
    TFiber.Current.SwitchToMainThread;
  end;

end;
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Fr 02.04.10 17:41 
Das ist zu hoch für 99.9% aller Programmierer.

_________________
Na denn, dann. Bis dann, denn.
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Fr 02.04.10 17:58 
Nicht unbedingt zu hoch, aber sowas ohne echte Sprachfeatures zu machen, ist irgendwie... unschön.

Vielleicht könnte man da mit den DLangExtensions was machen?

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Webo
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 577
Erhaltene Danke: 14

Win 7, Debian
C# (Visual Studio 2013), PHP, C, C++ (Eclipse, KDevelop)
BeitragVerfasst: Fr 02.04.10 19:01 
Jetzt, wie ich mir den Eingangstext so durchgelesen habe scheint das ein sehr interessantes Thema zu sein. Auch wenn ich direkt nicht weiß, wo ich sowas einbauen könnte, ich werde gleich mal damit rumspielen. Mal schauen was sich so ergibt 8)

_________________
Man kann nur das aus dem Ärmel schütteln, was man auch vorher reingesteckt hat.
delfiphan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Fr 02.04.10 19:03 
Ich habe diese Library verwendet, um bestehenden Code multi-threaded zu machen. Z.B. wechsle ich bei langen DB-Queries schnell in einen WorkerThread (Achtung, die DB-Library muss natürlich Thread-Safe sein!). Wenn die Query fertig ist, geht es wieder weiter mit dem bestehenden Kontrollfluss im MainThread. Interessant auch bei blockierenden Calls bei Indy-Komponenten.

Kompliziert ist das ganze nicht, zu mindest nicht in der Anwendung. Im Gegenteil, es soll Threading vereinfachen.

Wenn man mit TThread was machen will, muss man ja:
- Von TThread ableiten. Der Code, der im Thread läuft in eine Execute-Methode packen.
- Informationen, die der Thread braucht muss man separat übergeben z.B. über public Properties in der abgeleiteten Klasse.
- Um die Kontrolle zurück an den MainThread zu geben muss man Synchronize verwenden. Die nimmt wieder nur Methoden ohne Argumente entgegen. Man muss wieder mit irgend welchen privaten Variablen arbeiten, die vielleicht nur temporärer Natur sind.
- Bei Exceptions im Thread muss man die selbst wieder an den MainThread kommunizieren.

user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
sowas ohne echte Sprachfeatures zu machen, ist irgendwie... unschön.

Da gebe ich dir Recht. Ich würde so eine Funktionalität auch nicht in die RTL/VCL aufnehmen, wenn ich bei Borland arbeiten würde. Aber praktisch finde ich die Library trotzdem.
Webo
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 577
Erhaltene Danke: 14

Win 7, Debian
C# (Visual Studio 2013), PHP, C, C++ (Eclipse, KDevelop)
BeitragVerfasst: Fr 02.04.10 19:31 
user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
Kompliziert ist das ganze nicht, zu mindest nicht in der Anwendung. Im Gegenteil, es soll Threading vereinfachen.

Das ist wohl war. Ich habe grade mal ein bisschen getestet und muss sagen: Werde ich jetzt öfters anwenden. Ist ja ein Kinderspiel damit, Sachen in Threads auszulagern ;-)

_________________
Man kann nur das aus dem Ärmel schütteln, was man auch vorher reingesteckt hat.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 02.04.10 19:51 
user profile iconWebo hat folgendes geschrieben Zum zitierten Posting springen:
user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
Kompliziert ist das ganze nicht, zu mindest nicht in der Anwendung. Im Gegenteil, es soll Threading vereinfachen.

Das ist wohl war. Ich habe grade mal ein bisschen getestet und muss sagen: Werde ich jetzt öfters anwenden. Ist ja ein Kinderspiel damit, Sachen in Threads auszulagern ;-)

Vorsicht! Fibers sind keine Threads!
www.michael-puff.de/...ich9.html#x38-540009
Webo
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 577
Erhaltene Danke: 14

Win 7, Debian
C# (Visual Studio 2013), PHP, C, C++ (Eclipse, KDevelop)
BeitragVerfasst: Fr 02.04.10 20:27 
user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
Vorsicht! Fibers sind keine Threads!

Geht klar Meister :flehan: (:)) ... dann ist es eben "ein Kinderspiel, Sachen in Pseudo-Threads auszulagern". Nee, Spaß beiseite, danke der Richtigstellung, man will ja dazu lernen.
Ob Pseudo-Thread oder nicht, aufjedenfall eine sehr nette Sache.

_________________
Man kann nur das aus dem Ärmel schütteln, was man auch vorher reingesteckt hat.


Zuletzt bearbeitet von Webo am Sa 03.04.10 10:07, insgesamt 1-mal bearbeitet
delfiphan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Fr 02.04.10 20:49 
Fibers sind keine Threads, das wurde hier nirgends behauptet. Wenn ich oben von Threads oder Threading spreche, meine ich auch Threads.

In dieser Library geht es darum, mittels Fibers Threading zu vereinfachen. Die Vereinfachung resultiert daraus, dass man jeweils selbst wählen kann, in welchem Thread ein bestimmter Fiber läuft und den Thread auch jederzeit wechseln kann.

Diese Library enthält TFiber, eine Klasse, die Fibers implementiert. Diese, zusammen mit anderen Klassen in der Library, vereinfachen Threading.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 02.04.10 21:27 
user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
Fibers sind keine Threads, das wurde hier nirgends behauptet.

Dich meinte ich ja auch gar nicht, sondern Webo.
delfiphan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Sa 30.10.10 09:43 
Hab die API noch ein wenig angepasst für Leute mit einer neueren Version von Delphi. Man kann einen Fiber nun als anonyme Methode von irgendwo aus starten.

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
procedure TForm1.Button1Click(Sender: TObject);
begin

  TFiber.Run(
    procedure
    var
      I: Integer;
    begin
      (Sender as TButton).Caption := 'Calculating...';

      TFiber.Current.SwitchToWorkerThread;
      try
        // slow operation here
        for I := 0 to 99 do
          Sleep(100);
      finally
        TFiber.Current.SwitchToMainThread;
      end;

      (Sender as TButton).Caption := 'Calculation completed';
    end
  );

end;


Zuletzt bearbeitet von delfiphan am So 31.10.10 15:42, insgesamt 1-mal bearbeitet
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 31.10.10 00:47 
Sollte das Switchen zwischen MainFiber und TaskFiber nicht von der Fiber-Klasse realisiert werden? Also zumindest für die Initialisierung und Finalisierung des Fibers?

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: So 31.10.10 11:11 
Interessante Klasse, ich werde mal Versuchen das ganze zu verstehen.
delfiphan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: So 31.10.10 13:43 
user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
Sollte das Switchen zwischen MainFiber und TaskFiber nicht von der Fiber-Klasse realisiert werden? Also zumindest für die Initialisierung und Finalisierung des Fibers?

Ich versteh nicht ganz; es gibt (im Beispiel oben) nur einen Fiber. Der Fiber wird dann auf dem einen oder anderen Thread ausgeführt.

Ich hab jetzt die API für die 2010er Version vereinfacht, sodass es nur noch 1 Klasse gibt (TFiber).

Zum Ausführen in einem Fiber:
TFiber.Run(<anonyme Methode>)

Innerhalb eines Fibers kann über TFiber.Current auf die aktuelle Instanz zugegriffen werden.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 31.10.10 17:52 
Mich hatten die SwitchToMainThread und SwitchToWorkerThread-Aufrufe etwas irritiert. Daher die Frage.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
delfiphan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: So 31.10.10 18:10 
SwitchToMainThread und SwitchToWorkerThread wird ja von der Fiber-Klasse realisiert. Die Methoden werden von der aktuellen Fiber-Instanz ausgeführt. Die aktuelle Instanz wird über TFiber.Current abgerufen. (Die ehem. TAnonymousFiber-Klasse leitete von TFiber ab, daher hat TFiber.Current die TAnonymousFiber-Instanz zurückgegeben. Die Klasse gibt's jetzt aber nicht mehr).

Sieht vielleicht auf den ersten Blick ungewöhnlich aus, aber schlussendlich spart es Tipparbeit. Mit der Klasse kann ich "freihändig" Fibers und Threads nutzen, d. h. ich muss weder eine Variable deklarieren noch eine Klasse implementieren. Um das Beispiel oben mit TThread zu realisieren, müsste man zuerst eine Klasse schreiben (von TThread ableiten), den Button als Feld zuweisen, die Methode Execute overriden und darin am Schluss wieder Synchronize aufrufen, um den Button-Text wieder anzupassen. Das ganze Exception-Handling im Thread kommt noch hinzu. Viel zu viel Aufwand für Implemenation, Testen und Wartung; ausserdem ist der Code nicht wirklich lesbarer. (bei dieser Argumentation müsste man sich aber fragen, ob Delphi die richtige Sprache dafür ist).
Fiji
Hält's aus hier
Beiträge: 1



BeitragVerfasst: So 27.07.14 14:32 
It seems it will not work with 64 bit.