-
Pl
chevron_right
Christian Hergert: Scheduling & Fibers
news.movim.eu / PlanetGnome • 3 September • 2 minutes
Previously , and previously .
Schedulers
The Dex.Scheduler is responsible for running work items on a thread. This is performed by integrating with the threads GMainContext . The main thread of your application will have a Dex.MainScheduler as the assigned scheduler.
The scheduler manages callbacks such as work items created with Dex.Scheduler.push() . This can include blocks, fibers, and application provided work.
You can get the default scheduler for the application’s main thread using Dex.Scheduler.get_default() . The current thread’s scheduler can be retrieved with Dex.Scheduler.ref_thread_default() .
Thread Pool Scheduling
Libdex manages a thread pool which may be retrieved using Dex.ThreadPoolScheduler.get_default() .
The thread pool scheduler will manage a number of threads that is deemed useful based on the number of CPU available. When
io_uring
is used, it will also restrict the number of workers to the number of
uring
available.
Work items created from outside of the thread pool are placed into a global queue. Thread pool workers will take items from the global queue when they have no more items to process.
To avoid “thundering herd” situations often caused by global queues and thread pools a pollable semaphore is used. On
Linux
, specifically,
io_uring
and eventfd combined with
EFD_SEMAPHORE
allow waking up a single worker when a work item is queued.
All thread pool workers have a local Dex.Scheduler so use of timeouts and other GSource features continue to work.
If you need to interact with long-blocking API calls it is better to use Dex.thread_spawn() rather than a thread pool thread.
Thread pool workers use a work-stealing wait-free queue which allows the worker to push work items onto one side of the queue quickly. Doing so also helps improve cacheline effectiveness.
Fibers
Fibers are a type of stackfull co-routine . A new stack is created and a trampoline is performed onto the stack from the current thread.
Use Dex.Scheduler.spawn() to create a new fiber.
When a fiber calls one of the Dex.Future.await() functions or when it returns the fiber is suspended and execution returns to the scheduler.
By default, fibers have a 128-kb stack with a guard page at the end. Fiber stacks are pooled so that they may be reused during heavy use.
Fibers are a Dex.Future which means you can await the completion of a fiber just like any other future.
Note that fibers are pinned to a scheduler. They will not be migrated between schedulers even when a thread pool is in use.
Fiber Cancellation
Fibers may be cancelled if the fiber has been discarded by all futures awaiting completion. Fibers will always exit through a natural exit point such as a pending “await”. All attempts to await will reject with error once a fiber has been cancelled.
If you want to ignore cancellation of fibers, use Dex.Future.disown() on the fiber after creation.
This article can be found at scheduling in the libdex documentation.