#thread-local #worker-thread #async-context

async-local

For using thread locals within an async context and across await points

20 releases (11 stable)

Uses new Rust 2024

4.0.0 Mar 3, 2025
3.0.2 Feb 23, 2025
2.0.1 Mar 24, 2024
2.0.0 Oct 19, 2023
0.3.0 Nov 30, 2022

#188 in Concurrency

Download history 170/week @ 2024-11-20 128/week @ 2024-11-27 123/week @ 2024-12-04 108/week @ 2024-12-11 118/week @ 2024-12-18 34/week @ 2024-12-25 48/week @ 2025-01-01 83/week @ 2025-01-08 97/week @ 2025-01-15 43/week @ 2025-01-22 171/week @ 2025-01-29 170/week @ 2025-02-05 76/week @ 2025-02-12 594/week @ 2025-02-19 379/week @ 2025-02-26 208/week @ 2025-03-05

1,273 downloads per month
Used in 3 crates (2 directly)

MIT license

22KB
404 lines

Async Local

License Cargo Documentation

Unlocking the potential of thread-locals in an async context

This crate enables references to thread locals to be used in an async context and across await points or within blocking threads managed by the Tokio runtime

How it works

By configuring Tokio with a barrier to rendezvous worker threads during shutdown, it can be gauranteed that no task will outlive thread local data belonging to worker threads. With this, pointers to thread locals constrained by invariant lifetimes are guaranteed to be of a valid lifetime suitable for use accross await points.

Runtime Configuration (optional)

In order to enable the optimization this crate provides, use the Tokio runtime as configured via the tokio::main or tokio::test macro with crate set as async_local while the barrier-protected-runtime feature flag is enabled.

Example usage

#[cfg(test)]
mod tests {
  use std::sync::atomic::{AtomicUsize, Ordering};

  use async_local::{AsyncLocal, Context};
  use generativity::make_guard;
  use tokio::task::yield_now;

  thread_local! {
      static COUNTER: Context<AtomicUsize> = Context::new(AtomicUsize::new(0));
  }

  #[tokio::test(crate = "async_local", flavor = "multi_thread")]
  async fn it_increments() {
    make_guard!(guard);
    let counter = COUNTER.local_ref(guard);
    yield_now().await;
    counter.fetch_add(1, Ordering::SeqCst);
  }
}

Dependencies

~0.3–24MB
~330K SLoC