Am 06.02.2014 20:24, schrieb Kelet:

Hello,

I'm new to both asynchronous i/o and fibers. I'm trying to grok on a high-level how fiber scheduling works in vibe-d.

As I understand, Fibers in DLang must be called, and then somewhere within the Fiber it must yield or naturally end if it wants to relinquish control back to the caller. The idea is that a Fiber scheduler could take some aggregate of Fibers and run them in an efficient way.

I'm interested in studying vibe-d's approach to this fiber scheduling problem. However, I'm a bit hazy even after reading the source code – it seems to be above my head.

My understanding, which is most definitely flawed (feel free to correct!), is that

  • There is a queue of Fibers (or some derivative of Fibers)
  • If a Fiber issues a vibe sleep(), a driver timer (say libevent) is created, and during the sleep time, events are processed (the event loop goes through some iterations). When the timer goes off, the Fiber is called again and resumes. Perhaps some other blocking operations are similar.
  • If a Fiber yields or ends, events are processed and the next Fiber in the queue is called. If it was a yield, it is placed in the back of the queue. If it ended, it is removed from the queue.
  • Each Thread probably has its own Fiber scheduler.

Sounds all about right.

And some things I can't figure out:

  • When and where are the new Fibers added to the Fiber 'queue'?

They are basically added only when yield() is explicitly called by the
user. As long as only blocking operations cause a task/fiber to yield,
it's the OS/event loop which determines which fiber will be resumed in
which order.

  • Why is there so much timer code in the drivers? I can't think of much use except for making a timer for when Fibers sleep.

The code guarantees that each timer uses up a minimum amount of memory
(only one OS timer is used), so that it can be guaranteed that timers
are light-weight and can be used safely in large numbers.

  • Does each Thread have its own Fiber queue so to speak?

Yes, also, as Stefan already said, a fiber is always exclusive to the
thread in which it was created, so fibers are never transferred between
threads. This is necessary to not break D's threading model (shared
and thread-local storage).

  • How are Fibers balanced between Threads when worker threads are enabled?

It depends. For the normal runWorkerTask, the first worker thread that
becomes idle will pick up the task an process it, so that usually all
threads will have a similar workload. In case of thread-distributed HTTP
request processing (HTTPServerOption.distribute), it's again the
OS/event loop which decides what thread will accept each incoming
connection.

Now obviously I'm not looking for an exacting in-depth technical description, just a high-level description or psuedocode with the major points, because I feel like I'm really missing out on some fundamental understanding. I'm currently more interested in fiber scheduling because as it stands, I know I'm missing some significant chunks.

Regards,
Kelet

A final note that hasn't been mentioned, each fiber can be reused for
multiple tasks in sequence. So whenever a task has finished, the
corresponding fiber will be yielded and then can be reused later for
another task.

In the end the concept is really quite simple. But I'll also write up a
small article about how this works (it has been planned for a long
time), but the time currently doesn't really permit that and there are
still a few unknowns that I'd like to carve out first (mostly w.r.t
WinRT) before finally fully committing to a certain model (it's already
99% certain, though).