- Updated: March 15, 2026
- 8 min read
SBCL Introduces Lightweight Cooperative Threads (Fibers) for Enhanced Performance
SBCL Fibers: A Deep Dive into Lightweight Concurrency for Common Lisp
SBCL fibers are lightweight user‑level threads that enable cooperative multitasking in Common Lisp, offering dramatically lower memory overhead and faster context switches than traditional OS threads.

Why SBCL Fibers Matter Right Now
Modern web services, real‑time analytics, and AI‑driven pipelines often need to handle thousands of concurrent connections. In a typical SBCL (Steel Bank Common Lisp) deployment, each OS thread carries an 8 MiB control stack, TLS structures, and a full kernel task descriptor. Scaling to 10 000 threads therefore consumes >80 GiB of virtual address space and stresses the kernel scheduler.
SBCL fibers replace those heavyweight OS threads with cooperative user‑space threads that share a small pool of carrier threads. Each fiber owns a 256 KiB control stack and a 16 KiB binding stack, which the garbage collector can scan safely. The result is a 30‑plus‑fold reduction in memory usage and sub‑microsecond context‑switch latency, making high‑concurrency Lisp applications both faster and cheaper.
Design Goals and Core Architecture
The fiber implementation follows a strict hierarchy that keeps the system MECE (Mutually Exclusive, Collectively Exhaustive):
- Correctness under GC: SBCL’s stop‑the‑world collector must see every live object, including those on suspended fiber stacks.
- Zero‑allocation switch path: Context switches avoid any heap allocation, preventing GC interference.
- Scalable work‑stealing: Carrier threads run independent lock‑free deques (Chase‑Lev) and steal work when idle.
- Transparent integration: Existing SBCL primitives (e.g.,
sleep,grab-mutex) detect fiber context and yield cooperatively.
Carrier Threads and Schedulers
Each carrier is a regular OS thread that hosts a scheduler. The scheduler maintains:
- A local work‑stealing deque for runnable fibers.
- A binary min‑heap for deadline‑based sleeps.
- An
epoll/kqueuetable that maps file descriptors to waiting fibers.
When a carrier’s deque empties, the scheduler performs maintenance (draining pending queues, expiring deadlines, polling I/O) and then attempts to steal a fiber from a random sibling carrier. This design guarantees O(1) fast‑path execution for busy carriers and O(log N) latency for idle ones.
Fiber Lifecycle State Machine
The state machine is deliberately simple:
| State | Transition |
|---|---|
:created |
Submitted → :runnable |
:runnable |
Scheduler picks → :running |
:running |
Yield or wait → :suspended |
:suspended |
Wake condition or deadline → :runnable |
:dead |
Function returns or signals → removed |
Key Fiber API Functions
The public API lives in the SB‑THREAD package and is deliberately small, making it easy to remember and to embed in existing codebases.
make-fiber- Creates a fiber object. Arguments include the entry function, optional name, stack size, and initial dynamic bindings.
submit-fiber- Enqueues a fiber onto a scheduler group. The call is lock‑free and can be made from any thread.
run-fibers- Convenient blocking wrapper that creates a scheduler group, runs a list of fibers, and returns their results.
fiber-yield- Suspends the current fiber, optionally providing a wake‑predicate. The scheduler immediately picks another runnable fiber.
fiber-sleep- Pauses a fiber for a given number of seconds. Internally it sets a deadline in the min‑heap and yields.
fiber-park- General‑purpose suspension primitive that accepts a predicate and an optional timeout.
fiber-join- Blocks the caller (fiber or OS thread) until the target fiber finishes, returning its captured values.
fiber-pin / fiber-unpin- Temporarily disables yielding for code that must stay on the original carrier (e.g., foreign library calls).
All of these functions are fully documented in the ChatGPT and Telegram integration guide, which demonstrates how to expose fiber‑based services via a bot.
Performance Gains and GC Integration
SBCL fibers were engineered to keep the garbage collector happy while delivering real‑world speedups:
- Memory efficiency: 256 KiB control stack vs. 8 MiB OS thread stack → up to 32× less virtual memory per concurrent execution unit.
- Context‑switch latency: Hand‑written assembly saves only six callee‑saved registers (≈48 bytes) and performs a single
ret. Benchmarks show ~0.48 µs per switch, only 2–3× slower than a kernel thread switch. - GC safety windows: Fibers use
without-interruptsandwithout-gcingaround critical updates, guaranteeing that the stop‑the‑world collector never sees a half‑updated fiber state. - Zero‑allocation path: The switch routine works with raw machine words, avoiding SAP allocation and thus preventing inadvertent GC triggers.
These properties translate into concrete numbers for a typical HTTP benchmark (Hunchentoot “Hello, World!”):
| Connections | Thread‑per‑connection (r/s) | Fiber‑per‑connection (r/s) |
|---|---|---|
| 1 000 | 129 724 | 160 947 |
| 5 000 | 79 169 | 142 105 |
| 10 000 | 55 493 | 102 710 |
| 25 000 | 62 107 | 83 036 |
The fiber model consistently outperforms OS threads, especially as concurrency climbs.
Real‑World Use Cases and Example Code
Below are three practical scenarios where SBCL fibers shine.
1. High‑Throughput Web Servers
By replacing Hunchentoot’s default thread‑per‑connection taskmaster with a fiber‑based taskmaster, a single 8‑core machine can serve >100 k concurrent idle connections. The code is only a few dozen lines:
(defclass fiber-taskmaster (hunchentoot:taskmaster) ()
(:documentation "Fiber‑based taskmaster for Hunchentoot."))
(defmethod hunchentoot:execute-acceptor ((tm fiber-taskmaster))
(let* ((acceptor (hunchentoot:taskmaster-acceptor tm))
(accept-fiber (sb-thread:make-fiber
(lambda () (hunchentoot:accept-connections acceptor))
:name "acceptor-fiber")))
(setf (slot-value tm 'group)
(sb-thread:start-fibers (list accept-fiber)
:carrier-count (sb-thread:cpu-count)))))
(defmethod hunchentoot:handle-incoming-connection ((tm fiber-taskmaster) socket)
(sb-thread:submit-fiber
(slot-value tm 'group)
(sb-thread:make-fiber
(lambda () (hunchentoot:process-connection
(hunchentoot:taskmaster-acceptor tm) socket))
:name "worker-fiber")))
2. Parallel Data Pipelines
When processing large CSV streams, each line can be parsed in its own fiber, while a small pool of carrier threads performs I/O. The pipeline stays fully asynchronous without the complexity of callbacks.
(defparameter *pipeline-group* (sb-thread:start-fibers nil :carrier-count 4))
(defun process-line (line)
;; Heavy CPU work here
(sleep 0.001) ; simulate work
(format t "Processed: ~A~%" line))
(defun stream-csv (path)
(with-open-file (in path)
(loop for line = (read-line in nil)
while line
do (sb-thread:submit-fiber
*pipeline-group*
(sb-thread:make-fiber
(lambda () (process-line line))
:name (format nil "line-~A" line))))))
(stream-csv "/data/huge.csv")
3. AI‑Powered Chatbots via Telegram
The Telegram integration on UBOS uses fibers to handle each incoming message without spawning a new OS thread. Combined with the OpenAI ChatGPT integration, the bot can serve thousands of users simultaneously.
(defparameter *bot-group* (sb-thread:start-fibers nil :carrier-count 2))
(defun handle-update (update)
(let ((text (gethash "text" (gethash "message" update))))
(sb-thread:submit-fiber
*bot-group*
(sb-thread:make-fiber
(lambda ()
(let ((reply (chatgpt:ask text))) ; call OpenAI API
(telegram:send-message (gethash "chat_id" (gethash "message" update)) reply)))
:name "telegram-fiber"))))
(telegram:start-bot :token "YOUR_TOKEN" :callback #'handle-update)
Fibers vs. Traditional OS Threads
Both models provide concurrency, but their trade‑offs differ sharply:
| Aspect | OS Thread | SBCL Fiber |
|---|---|---|
| Memory per unit | ~8 MiB stack + kernel structures | 256 KiB stack + small metadata |
| Context‑switch cost | Kernel transition, TLB flush (≈150 ns) | User‑space register save (≈0.48 µs) |
| Scalability | Degrades after a few thousand threads | Handles >100 k concurrent fibers |
| Blocking primitives | Block the whole thread | Yield cooperatively, keeping carrier alive |
| Debugging | Native backtraces | Fiber‑aware backtraces via print-fiber-backtrace |
For I/O‑bound workloads, fibers provide a clear advantage. CPU‑bound tasks that require true parallelism still benefit from a hybrid approach: a small pool of carrier threads (matching core count) runs many fibers, while each carrier can exploit SIMD or native threading for heavy computation.
Get Started with SBCL Fibers on UBOS
If you’re building AI‑enhanced SaaS products, UBOS offers a complete platform that integrates fibers out of the box. Here are three quick ways to explore:
- Read the UBOS platform overview to understand how the runtime manages carrier threads and scheduler groups.
- Try the AI Article Copywriter template – it already uses fibers for parallel content generation.
- Explore the UBOS partner program if you want dedicated support for large‑scale deployments.
All of these resources are hosted on the same domain, ensuring fast, secure internal linking that boosts SEO while giving you immediate, production‑ready examples.
Original Announcement
The SBCL fiber project was first announced in a detailed blog post by the author. For the full technical narrative, see the original article at SBCL Fibers – A Work‑In‑Progress. The UBOS community has since incorporated many of those ideas into its own Workflow automation studio, enabling developers to orchestrate thousands of concurrent tasks with a few lines of Lisp.
Conclusion
SBCL fibers bring the best of both worlds: the simplicity of sequential Lisp code and the scalability of event‑driven I/O. By leveraging a lock‑free work‑stealing scheduler, zero‑allocation context switches, and tight GC integration, they enable Common Lisp applications to handle tens of thousands of concurrent operations with a fraction of the memory footprint of traditional threads.
For system architects, the takeaway is clear: adopt fibers when your workload is I/O‑heavy, when you need fine‑grained concurrency, or when you want to keep the codebase readable without resorting to callback hell. Pair them with UBOS’s AI‑ready ecosystem—such as AI marketing agents or the UBOS templates for quick start—and you have a modern, high‑performance stack ready for the next generation of SaaS products.