🦀🚀 Abstract over `Send` and `!Send` traits crates.io/crates/future_form
future_form DESIGN.md
1.8 kB
Markdown

Design Notes #

Performance Impact of Boxing Futures #

future_form uses BoxFuture and LocalBoxFuture under the hood. This section discusses the performance implications of that choice.

Costs #

Allocation

  • One heap allocation per boxed future (typically small, but adds up in hot paths)
  • Deallocation when the future completes

Indirection

  • Virtual dispatch through the dyn Future trait object on each poll
  • Pointer chasing can hurt CPU cache locality

In Practice #

The impact is often negligible because:

  1. Futures are usually polled relatively few times compared to the work they represent
  2. A single network call or disk read dwarfs the cost of one allocation
  3. The allocator is highly optimized for small, short-lived allocations

When It Matters #

  • Tight loops spawning thousands of tiny futures
  • Latency-critical code paths (microsecond-level)
  • Embedded/no_std environments with constrained allocators

Alternatives #

Approach Tradeoff
async-trait Same cost (also boxes)
impl Future (static dispatch) Avoids boxing but can't be used in trait objects or with this kind of abstraction
Enum-based dispatch Works for a fixed set of variants, but doesn't generalize

Recommendation #

For most async code doing I/O, the boxing cost is noise. If profiling shows it's a bottleneck, you'd typically avoid the abstraction entirely in that hot path rather than try to optimize the boxing.