Fiber Pooling With NeverBlock
As mentioned in my earlier introduction about fibers I will be talking today about the fiber pooling features that are implemented as part of the NeverBlock library.
The fiber pool is implemented as the NeverBlock::Pool::FiberPool class. The interface is super easy, with only one public method spawn that is. Here’s an example
The spawn method take only one argument, which is a code block to be run as a fiber. The spawned fiber will resume immediately (that is, if the pool managed to find us a free fiber immediately).
How does the pooling work then?
Initially when you create a new pool all the fibers will be created in advance (we can consider a lazy generation option later). They are all stored in an array and the pool waits for requests. Once the method spawn is called the pool checks the fibers array, if it can find any, it takes a fiber out of the array and resumes it with the block as the parameter. If no fibers are present at the moment the block is put in a queue for later processing.
Here’s how the spawn method is written:
Once the fibers are first initialized they are given a non-ending loop that attempts to run blocks in the following manner:
Whenever you call resume on such a fiber and pass a block, the block will be called and when done the fiber will yield control back again.
But how will the fiber ever become avialable again in the @fibers array? glad you noticed. The actual implementation is a little different
The only caveat here is that our spawn method no longer returns the value of running the fiber. But that was the case with queued blocks any way so it’s no big deal.
While fibers are cheaper than threads, they still come at a memory and performance cost. Using a pool makes sure your memory usage is controlled and that not too many transient fibers are created. Coming up for this pool is the ability to grow and shrink the fiber count based on usage. By defining minimum and maximum sizes rather than a single size the pool should be able to move between those values to accommodate different work loads.
