Fiber - Crystal 1.20.2

# class Fiber

- Fiber
- Reference
- Object

##
Overview

A `Fiber` is a light-weight execution unit managed by the Crystal runtime.

It is conceptually similar to an operating system thread but with less overhead and completely internal to the Crystal process. The runtime includes a scheduler which schedules execution of fibers.

A `Fiber` has a stack size of `8 MiB` which is usually also assigned to an operating system thread. But only `4KiB` are actually allocated at first so the memory footprint is very small.

Communication between fibers is usually passed through `Channel`.

##
Cooperative

Fibers are cooperative. That means execution can only be drawn from a fiber when it offers it. It can't be interrupted in its execution at random. In order to make concurrency work, fibers must make sure to occasionally provide hooks for the scheduler to swap in other fibers. IO operations like reading from a file descriptor are natural implementations for this and the developer does not need to take further action on that. When IO access can't be served immediately by a buffer, the fiber will automatically wait and yield execution. When IO is ready it's going to be resumed through the event loop.

When a computation-intensive task has none or only rare IO operations, a fiber should explicitly offer to yield execution from time to time using `Fiber.yield` to break up tight loops. The frequency of this call depends on the application and concurrency model.

##
Event loop

The event loop is responsible for keeping track of sleeping fibers waiting for notifications that IO is ready or a timeout reached. When a fiber can be woken, the event loop enqueues it in the scheduler

##
Defined in:

fiber.cr
fiber/context.cr
fiber/context/aarch64-generic.cr
fiber/execution_context/thread_pool.cr
fiber/list.cr
fiber/pointer_linked_list_node.cr
fiber/stack.cr
fiber/stack_pool.cr
log/metadata.cr

##
Constructors

- .current : Fiber

  Returns the current fiber.

- .new(name : String | Nil = nil, &proc : -> ) : self

  Creates a new `Fiber` instance.

##
Class Method Summary

- .suspend : Nil

  Suspends execution of the current fiber indefinitely.

- .yield : Nil

  Yields to the scheduler and allows it to swap execution to other waiting fibers.

##
Instance Method Summary

- #dead? : Bool

  The fiber's proc has terminated, and the fiber is now considered dead.

- #enqueue : Nil

  Adds this fiber to the scheduler's runnables queue for the current thread.

- #inspect(io : IO) : Nil

  Appends a String representation of this object which includes its class name, its object address and the values of all instance variables.

- #name : String | Nil

  The name of the fiber, used as internal reference.

- #name=(name : String | Nil)

  The name of the fiber, used as internal reference.

- #resumable? : Bool

  The fiber's proc is currently not running and fully saved its context.

- #resume : Nil

  Immediately resumes execution of this fiber.

- #running? : Bool

  The fiber's proc is currently running or didn't fully save its context.

- #to_s(io : IO) : Nil

  Appends a short String representation of this object which includes its class name and its object address.

### Instance methods inherited from class `Reference`

==(other : self)
==(other : JSON::Any)
==(other : YAML::Any)
==(other) ==, dup dup, hash(hasher) hash, initialize initialize, inspect(io : IO) : Nil inspect, object_id : UInt64 object_id, pretty_print(pp) : Nil pretty_print, same?(other : Reference) : Bool
same?(other : Nil) same?, to_s(io : IO) : Nil to_s

### Constructor methods inherited from class `Reference`

new new, unsafe_construct(address : Pointer, *args, **opts) : self unsafe_construct

### Class methods inherited from class `Reference`

pre_initialize(address : Pointer) pre_initialize

### Instance methods inherited from class `Object`

! : Bool !, !=(other) !=, !~(other) !~, ==(other) ==, ===(other : JSON::Any)
===(other : YAML::Any)
===(other) ===, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash hash, in?(collection : Object) : Bool
in?(*values : Object) : Bool in?, inspect(io : IO) : Nil
inspect : String inspect, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil!(message)
not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO) : Nil
to_json : String to_json, to_pretty_json(indent : String = " ") : String
to_pretty_json(io : IO, indent : String = " ") : Nil to_pretty_json, to_s(io : IO) : Nil
to_s : String to_s, to_yaml(io : IO) : Nil
to_yaml : String to_yaml, try(&) try, unsafe_as(type : T.class) forall T unsafe_as

### Class methods inherited from class `Object`

from_json(string_or_io : String | IO, root : String)
from_json(string_or_io : String | IO) from_json, from_yaml(string_or_io : String | IO) from_yaml

### Macros inherited from class `Object`

class_getter(*names, &block) class_getter, class_getter!(*names) class_getter!, class_getter?(*names, &block) class_getter?, class_property(*names, &block) class_property, class_property!(*names) class_property!, class_property?(*names, &block) class_property?, class_setter(*names) class_setter, def_clone def_clone, def_equals(*fields) def_equals, def_equals_and_hash(*fields) def_equals_and_hash, def_hash(*fields) def_hash, delegate(*methods, to object) delegate, forward_missing_to(delegate) forward_missing_to, getter(*names, &block) getter, getter!(*names) getter!, getter?(*names, &block) getter?, property(*names, &block) property, property!(*names) property!, property?(*names, &block) property?, setter(*names) setter

##
Constructor Detail

def self.current : Fiber #

Returns the current fiber.

def self.new(name : String | Nil = nil, &proc : -> ) : self #

Creates a new `Fiber` instance.

When the fiber is executed, it runs proc in its context.

name is an optional and used only as an internal reference.

##
Class Method Detail

def self.suspend : Nil #

Suspends execution of the current fiber indefinitely.

Unlike `Fiber.yield` the current fiber is not automatically reenqueued and can only be resumed with an explicit call to `#enqueue`.

This is equivalent to `sleep` without a time.

This method is meant to be used in concurrency primitives. It's particularly useful if the fiber needs to wait for something to happen (for example an IO event, a message is ready in a channel, etc.) which triggers a re-enqueue.

def self.yield : Nil #

Yields to the scheduler and allows it to swap execution to other waiting fibers.

This is equivalent to `sleep 0.seconds`. It gives the scheduler an option to interrupt the current fiber's execution. If no other fibers are ready to be resumed, it immediately resumes the current fiber.

This method is particularly useful to break up tight loops which are only computation intensive and don't offer natural opportunities for swapping fibers as with IO operations.

    counter = 0
    spawn name: "status" do
      loop do
        puts "Status: #{counter}"
        sleep(2.seconds)
      end
    end

    while counter < Int32::MAX
      counter += 1
      if counter % 1_000_000 == 0
        # Without this, there would never be an opportunity to resume the status fiber
        Fiber.yield
      end
    end

##
Instance Method Detail

def dead? : Bool #

The fiber's proc has terminated, and the fiber is now considered dead. The fiber is impossible to resume, ever.

def enqueue : Nil #

Adds this fiber to the scheduler's runnables queue for the current thread.

This signals to the scheduler that the fiber is eligible for being resumed the next time it has the opportunity to reschedule to another fiber. There are no guarantees when that will happen.

def inspect(io : IO) : Nil #
Description copied from class Reference

Appends a String representation of this object which includes its class name, its object address and the values of all instance variables.

    class Person
      def initialize(@name : String, @age : Int32)
      end
    end

    Person.new("John", 32).inspect # => #<Person:0x10fd31f20 @name="John", @age=32>

def name : String | Nil #

The name of the fiber, used as internal reference.

def name=(name : String | Nil) #

The name of the fiber, used as internal reference.

def resumable? : Bool #

The fiber's proc is currently not running and fully saved its context. The fiber can be resumed safely.

def resume : Nil #

Immediately resumes execution of this fiber.

There are no provisions for resuming the current fiber (where this method is called). Unless it is explicitly added for rescheduling (for example using `#enqueue`) the current fiber won't ever reach any instructions after the call to this method.

    fiber = Fiber.new do
      puts "in fiber"
    end
    fiber.resume
    puts "never reached"

def running? : Bool #

The fiber's proc is currently running or didn't fully save its context. The fiber can't be resumed.

def to_s(io : IO) : Nil #
Description copied from class Reference

Appends a short String representation of this object which includes its class name and its object address.

    class Person
      def initialize(@name : String, @age : Int32)
      end
    end

    Person.new("John", 32).to_s # => #<Person:0x10a199f20>