#async-pool #pool #async #priority

piscina

A simple generic pool that supports both sync and async

5 releases

0.2.1 Feb 23, 2023
0.2.0 Feb 23, 2023
0.1.2 Feb 22, 2023
0.1.1 Feb 22, 2023
0.1.0 Feb 21, 2023

#320 in Asynchronous

Download history 357/week @ 2023-12-14 508/week @ 2023-12-21 455/week @ 2023-12-28 160/week @ 2024-01-04 605/week @ 2024-01-11 300/week @ 2024-01-18 365/week @ 2024-01-25 328/week @ 2024-02-01 334/week @ 2024-02-08 466/week @ 2024-02-15 309/week @ 2024-02-22 352/week @ 2024-02-29 702/week @ 2024-03-07 420/week @ 2024-03-14 473/week @ 2024-03-21 635/week @ 2024-03-28

2,339 downloads per month

MIT/Apache

56KB
1K SLoC

piscina

A simple generic pool that supports both sync and async.

crate_version docs_version

Two types of pools are provided:

  • Pool: A simple pool that supports both sync and async.
  • PriorityPool: A pool of items with priorities and supports both sync and async.

This crate internally utilizes futures_channel::oneshot and is thus lock-free.

Features

default = []

The features below are related to logging errors, which should be unreachable.

  • log: Enables logging using the log crate.
  • tracing: Enables logging using the tracing crate.

Examples

Non-async Pool example:

use piscina::Pool;

let mut pool = Pool::new();
pool.put(1);
pool.put(2);

let item1 = pool.try_get();
assert!(item1.is_some());

let item2 = pool.blocking_get();

let none = pool.try_get();
assert!(none.is_none());

drop(item1); // Return the item to the pool by dropping it
let item3 = pool.try_get();
assert!(item3.is_some());

Async Pool example:

use piscina::Pool;

futures::executor::block_on(async {
    let mut pool = Pool::new();
    pool.put(1);
    pool.put(2);

    let item1 = pool.get().await;
    let item2 = pool.get().await;

    let none = pool.try_get();
    assert!(none.is_none());

    drop(item1); // Return the item to the pool by dropping it
    let item3 = pool.get().await;
});

Non-async PriorityPool example:

use piscina::PriorityPool;

let mut pool = PriorityPool::new();
pool.put("hello", 1);
pool.put("world", 2); // Larger value means higher priority.

// Get the highest priority item.
let item = pool.try_get();
assert!(item.is_some());
let item = item.unwrap();
assert_eq!(item.item(), &"world");

let another_item = pool.try_get();
assert!(another_item.is_some());
let another_item = another_item.unwrap();
assert_eq!(another_item.item(), &"hello");

// The pool is now empty.
let empty_item = pool.try_get();
assert!(empty_item.is_none());

drop(another_item); // Return the item back to the pool by dropping it.
let hello = pool.try_get();
assert!(hello.is_some());
assert_eq!(hello.unwrap().item(), &"hello");

Async PriorityPool example:

use piscina::PriorityPool;

let mut pool = PriorityPool::new();
pool.put("hello", 1);
pool.put("world", 2); // Larger value means higher priority.

futures::executor::block_on(async {
    // Get the highest priority item.
    let world = pool.get().await;
    assert_eq!(world.item(), &"world");

    let hello = pool.get().await;
    assert_eq!(hello.item(), &"hello");

    // The pool is now empty.
    drop(hello); // Return the item back to the pool by dropping it.
    let item = pool.get().await;
    assert_eq!(item.item(), &"hello");
});

Safety

Instead of using an Option, this crate uses unsafe code ManuallyDrop in PooledItem. And the only use of unsafe code ManuallyDrop::take() occurs when PooledItem is dropped.

License: MIT/Apache-2.0

Dependencies

~0.6–0.9MB
~16K SLoC