Performance model
Breeze's speed comes from a handful of deliberate architectural choices, not from a single trick. Each one has a cost model you should understand before turning it on.
Inline execution
A non-blocking handler runs directly on the gnet event-loop goroutine that read the request: no worker-pool hop, no channel handoff, no AsyncWrite poller wakeup. This is the single largest throughput win in the
framework.
router.Handle(breeze.GET, "/users/:id", getUser) // inline โ the fast path app.SetInlineExecution(true) // default; false routes everything through the pool The rule: a handler registered with Handle must never block. If it
touches a database, the filesystem, or the network, register it with HandleBlocking instead so it runs on the worker pool โ otherwise it stalls
every other connection pinned to that same event loop.
Zero-copy headers (opt-in)
app.SetZeroCopyHeaders(true) Parses a request, routes it, handles it, and answers it with zero heap
allocations on the hot path. The trade-off is lifetime: header and body
strings point into a pooled read buffer for the duration of the handler
only. Anything kept past the handler's return โ logged after ctx.Next(),
stored in a map, sent to another goroutine โ must be copied first with strings.Clone or equivalent, or a later request on the same connection
will silently overwrite it.
Routing
O(1) exact-path routing via per-method buckets, with dynamic :params and
wildcard segments layered on top. See Router & Handlers.
Pooling
Everything hot is pooled: Context, HTTPRequest, HTTPResponse, wire
buffers, and route-param maps. Pooling is what keeps allocation counts flat
regardless of load โ the same reason the events bus holds allocation at
152 bytes / 3 allocs from 1 to 1000 listeners (see Events).
The worker pool
pool := breeze.NewEventLoopWorkerPool(runtime.NumCPU())
app := breeze.New(router, pool) A configurable pool for anything that blocks, with three backpressure policies for what happens when it is full:
| Policy | Behaviour when the pool is saturated |
|---|---|
Block | the caller waits for a free worker |
Reject | the submission fails immediately |
Spawn | a new goroutine is spawned for the task |
pool.Metrics() // WorkerPoolMetrics โ queue depth, active workers, rejects
pool.Shutdown(ctx) NewWorkerPool and NewWorkerPoolWithConfig give more control over sizing
and the overflow policy than the CPU-count default from NewEventLoopWorkerPool.
Choosing what to measure
Two axes matter independently: does the handler block, and do you need zero-copy semantics badly enough to accept the lifetime discipline it requires. Most applications get the bulk of the win from inline execution and pooling alone, and reach for zero-copy headers only after profiling shows header allocation as a real cost.