class Fiber

Fibers sind Primitiven zur Implementierung leichter kooperativer Nebenläufigkeit in Ruby. Grundsätzlich sind sie ein Mittel zur Erstellung von Codeblöcken, die wie Threads unterbrochen und fortgesetzt werden können. Der Hauptunterschied besteht darin, dass sie nie präemptiv unterbrochen werden und die Planung vom Programmierer und nicht von der VM durchgeführt werden muss.

Im Gegensatz zu anderen Stackless-Leichtgewichts-Nebenläufigkeitsmodellen verfügt jede Fiber über einen Stack. Dies ermöglicht es der Fiber, von tief verschachtelten Funktionsaufrufen innerhalb des Fiber-Blocks aus angehalten zu werden. Sehen Sie sich das Handbuch ruby(1) an, um die Größe des Fiber-Stacks zu konfigurieren.

Wenn eine Fiber erstellt wird, läuft sie nicht automatisch. Vielmehr muss sie explizit mit der Methode Fiber#resume zum Laufen aufgefordert werden. Der Code, der innerhalb der Fiber läuft, kann die Kontrolle aufgeben, indem er Fiber.yield aufruft, in welchem Fall die Kontrolle an den Aufrufer zurückgegeben wird (den Aufrufer von Fiber#resume).

Bei der Übergabe oder Beendigung gibt die Fiber den Wert des zuletzt ausgeführten Ausdrucks zurück.

Zum Beispiel

fiber = Fiber.new do
  Fiber.yield 1
  2
end

puts fiber.resume
puts fiber.resume
puts fiber.resume

ergibt

1
2
FiberError: dead fiber called

Die Methode Fiber#resume akzeptiert eine beliebige Anzahl von Parametern. Wenn es sich um den ersten Aufruf von resume handelt, werden diese als Blockargumente übergeben. Andernfalls sind sie der Rückgabewert des Aufrufs von Fiber.yield.

Beispiel

fiber = Fiber.new do |first|
  second = Fiber.yield first + 2
end

puts fiber.resume 10
puts fiber.resume 1_000_000
puts fiber.resume "The fiber will be dead before I can cause trouble"

ergibt

12
1000000
FiberError: dead fiber called

Nicht-blockierende Fibers

Das Konzept der nicht-blockierenden Fiber wurde in Ruby 3.0 eingeführt. Eine nicht-blockierende Fiber gibt die Kontrolle an andere Fibers ab, wenn sie auf eine Operation stößt, die die Fiber normalerweise blockieren würde (wie sleep oder das Warten auf einen anderen Prozess oder E/A). Dies ermöglicht es dem Scheduler, das Blockieren und Aufwecken (Fortsetzen) dieser Fiber zu handhaben, wenn sie fortfahren kann.

Damit eine Fiber sich nicht-blockierend verhält, muss sie in Fiber.new mit blocking: false (was der Standard ist) erstellt werden und Fiber.scheduler muss mit Fiber.set_scheduler gesetzt werden. Wenn Fiber.scheduler im aktuellen Thread nicht gesetzt ist, ist das Verhalten von blockierenden und nicht-blockierenden Fibers identisch.

Ruby stellt keine Scheduler-Klasse zur Verfügung: sie muss vom Benutzer implementiert werden und entspricht Fiber::Scheduler.

Es gibt auch die Methode Fiber.schedule, die erwartet, dass sie den angegebenen Block sofort nicht-blockierend ausführt. Ihre tatsächliche Implementierung liegt beim Scheduler.