Using fibers

Fibers are similar to threads, but are more lightweight and cooperative rather than pre-emptive. That is, a fiber must explicitly yield to pass control to another fiber, either by calling the yield function directly or through a function that yields for you (such as an I/O function). On the other hand, threads will be scheduled automatically by the operating system and may be interrupted at any time.

How to do it…

Let us execute the following steps:

  1. Create a fiber with new Fiber. You do not have to create a special storage location for your state because fibers automatically save and restore their own stacks, so regular local variables will work.
  2. Call Fiber.yield periodically inside your fiber to let other fibers run. The yield function will return control to the function that called the fiber.
  3. Pass messages to worker threads to perform long computations.
  4. The main function is responsible for scheduling the fibers. It should call the call function on the fibers when it is ready to resume their execution.

Take a look at the following code:

import core.thread;

int count;

void testFunction() {
  import std.stdio;
  count++;
  writeln("Fiber run count: ", count);
  Fiber.yield();
  writeln("Fiber recalled after yielding!");
}

void main() {
  auto fiber1 = new Fiber(&testFunction);
  auto fiber2 = new Fiber(&testFunction);

  // Call the fiber, this will return when it calls Fiber.yield
  fiber1.call();
  fiber2.call();

  // now it will resume execution from the last yield call
  fiber1.call();
  fiber2.call();
}

Running the program will print the following:

Fiber run count: 1
Fiber run count: 2
Fiber recalled after yielding!
Fiber recalled after yielding!

How it works…

A Fiber represents the execution context of a function that can be paused and resumed. It is created similar to a Thread, by first importing core.thread and then creating the Fiber by passing the constructor a pointer to the function.

However, after creation, Fibers and Threads work very differently. Whereas a Thread is started and then executes concurrently with other threads, a Fiber is called, like a function, with the flow of execution transferring to it. Unlike just any function though, a fiber can call Fiber.yield(), which returns the execution to the caller while remembering the exact state it had when it yielded. Next time the fiber is called, it picks up where it left off the last time.

Since fibers are cooperative when multitasking, they yield rather than being interrupted by the operating system. There is no need for memory synchronization or shared data. In the example, we used a thread-local variable, count, to represent a value across two separate fibers, and it was effortlessly updated by both. The downside to this model is that they do not utilize multiple CPU cores the way threads can, and thus do not help with parallelism. Nevertheless, fibers can sometimes outperform threads depending on the task. Asynchronous I/O is an example where fibers shine because they are not bound by the CPU.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.145.82