#hash-map #sharding #async #tokio

whirlwind

Collection of thread-safe, asynchronous data structures

3 releases

0.1.1 Nov 4, 2024
0.1.0 Nov 3, 2024
0.1.0-rc1 Nov 2, 2024

#227 in Asynchronous

Download history 125/week @ 2024-10-27 296/week @ 2024-11-03 25/week @ 2024-11-10 14/week @ 2024-11-17 2/week @ 2024-11-24 3/week @ 2024-12-01 34/week @ 2024-12-08

54 downloads per month

Apache-2.0

32KB
396 lines

🌀 Whirlwind

Build Status Crates.io Docs.rs License

An asynchronous, sharded HashMap for high-performance concurrent data access in Rust.

[!NOTE] This crate is in development, and breaking changes may be made up until a 1.0 release.

📖 Table of Contents

✨ Features

  • Async Ready: Seamless integration with Rust's async/await syntax.
  • High Performance: Sharding minimizes lock contention in concurrent environments.
  • Thread-safe: Safe for use across multiple threads without fear of data races.
  • Familiar API: Intuitive HashMap-like interface for ease of adoption.
  • Customizable Shards: Configure the number of shards to optimize for your workload.

📦 Installation

Add whirlwind to your Cargo.toml:

[dependencies]
whirlwind = "0.1.1"

🔧 Usage

Here's a quick example to get you started:

use whirlwind::ShardMap;

#[tokio::main]
async fn main() {
    let map = ShardMap::new();

    map.insert("apple", 3).await;
    map.insert("banana", 5).await;

    if let Some(quantity) = map.get(&"apple").await {
        println!("We have {} apples!", quantity);
    }

    map.remove(&"banana").await;
}

📚 Examples

Concurrent Inserts

use whirlwind::ShardMap;
use tokio::task::JoinSet;

#[tokio::main]
async fn main() {
    let map = ShardMap::new();
    let tasks: JoinSet<_> = (0..1000).map(|i| {
        let map = map.clone();
        tokio::spawn(async move {
            map.insert(i, i * 2).await;
        })
    }).collect();

    tasks.join_all().await.ok();

    assert_eq!(map.len().await, 1000);
}

Custom Shard Count

use whirlwind::ShardMap;

#[tokio::main]
async fn main() {
    let map = ShardMap::with_shards(64); // Initialize with 64 shards
    // Use the map as needed
}

📊 Benchmarks

Benchmarks were run in a asyncified version of this benchmark. You can find it here. Since the benchmarks use jonhoo/bustle, an asyncified fork of that library (here) is required.

Machine: Apple M3 Max (2023 16-inch MacBook Pro, 36GB RAM)

OS: macOS 15.0

See the results/ directory.

Read Heavy (std hasher)

Exchange (std hasher)

Rapid Grow (std hasher)

Read Heavy (ahash)

Exchange (ahash)

Rapid Grow (ahash)

🤝 Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository.
  2. Create a new branch: git checkout -b feature/your-feature.
  3. Commit your changes: git commit -am 'Add your feature'.
  4. Push to the branch: git push origin feature/your-feature.
  5. Open a pull request.

Running Tests

Ensure all tests pass before submitting a PR:

cargo test

Code Style

We use rustfmt for code formatting:

cargo fmt -- --check

License

Copyright 2024 Will Hopkins

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


Made with 💖 and Rust.

Dependencies

~1MB
~13K SLoC