Repository navigation
Description
A fresh OnceCell<usize> with an immediately ready initializer took 278 ms for six million initializations. The gap narrowed and the fastest peer changed when the initializer was already running and four other callers were waiting.
Apple M4 Max, macOS arm64, rustc 1.101.0-nightly. Each cell gives rank, elapsed time relative to Asyncband and the whole-batch median over 10 interleaved runs. Lower is faster. Supplemental measurements
| Scenario | Fixed rounds | Asyncband | Tokio | async-once-cell | async-lock |
|---|---|---|---|---|---|
| First initialization | 6,000,000 | #3, 1.00× (278 ms) | #2, 0.26× (71 ms) | #1, 0.22× (61 ms) | #4, 2.41× (672 ms) |
| Initialize with four waiting callers | 1,000,000 | #3, 1.00× (326 ms) | #1, 0.57× (187 ms) | #2, 0.88× (286 ms) | #4, 1.44× (472 ms) |
get_or_try_init checks the value, acquires a semaphore permit, checks again and publishes the result. An allocation counter measured one 64-byte allocation per cold initialization on this macOS host and zero for Tokio and async-once-cell. The first lock of a fresh std::sync::Mutex produced the same allocation. In a separate controlled run, changing only the internal lock implementation to parking_lot reduced Asyncband from 284 to 115 ms, with async-once-cell at 61 ms. The cost of already initialized reads is a separate measurement.
First contribution
Reproduce the cold and four-waiter rows and add an initialized-read control. Count allocations separately from timing. A focused patch can then target work done before any second caller arrives. Preserve publication of one value, retry after a cancelled or failed initializer, and progress for waiting callers.
To run the supplemental peer_checks command below, save and run peer-checks.rb from the linked comment in a disposable checkout of 6102089. The benchmark and library sources match 36ba6f2. Generator and instructions
cargo x bench --bench primitives -- once::get_or_init::initialize_cell --repeat 10 --raw
cargo x bench --bench peer_checks -- once-cell/initialize_cell --repeat 10 --raw
Activity
rokadepiyush49-rgb commentedon Nov 6, 2026
Could you assign this to me? I'd investigate
once::get_or_init::initialize_cellon an Apple M4 (10 cores, macOS 27.0.1), then repeat it on Linux.As a first check I ran a small standalone probe, not the benchmark. The 64-byte allocation looks macOS-specific: std uses the pthread
Mutexthere, which boxes on first lock, and the futex version on Linux.OnceCellreaches that lock becauseSemaphore::releaseseesavailable == 0after the only permit is taken.Over 6M rounds (rustc 1.94.1, median of 10), a fresh
Mutexwith one lock took 175 ms with one allocation. A freshRwLockwith one write took 15 ms with none. That roughly 160 ms gap is close to yourparking_lotresult, though that was on a different machine.cargo x benchalso builds the whole workspace, which enablesparking_lotfor Tokio throughtokio/full. If so, Tokio's rows may be using a different lock from Asyncband's, which could explain its zero allocations.Next I'd reproduce the cold and four-waiter rows with the initialized-read control. I haven't run those yet. I used Claude to help me read the code and write the probe.
tisonkun commentedon Nov 6, 2026
Thanks for your interest! We don't assign issues to individual contributors. Anyone is welcome to submit a PR directly for review.