Crates.io | lockfree-object-pool |
lib.rs | lockfree-object-pool |
version | 0.1.6 |
source | src |
created_at | 2021-01-21 07:28:58.633781 |
updated_at | 2024-05-19 13:25:35.828401 |
description | A thread-safe object pool collection with automatic return and attach/detach semantics. |
homepage | https://github.com/EVaillant/lockfree-object-pool |
repository | https://github.com/EVaillant/lockfree-object-pool |
max_upload_size | |
id | 344764 |
size | 73,041 |
A thread-safe object pool collection with automatic return.
Some implementations are lockfree :
Other use std::Mutex :
And NoneObjectPool basic allocation without pool.
[dependencies]
lockfree-object-pool = "0.1"
extern crate lockfree_object_pool;
The general pool creation looks like this for
let pool = LinearObjectPool::<u32>::new(
|| Default::default(),
|v| {*v = 0; });
And use the object pool
let mut item = pool.pull();
*item = 5;
...
At the end of the scope item return in object pool.
All implementations support same interface :
struct ObjectPool<T> {
}
impl<T> ObjectPool<T> {
// for LinearObjectPool, SpinLockObjectPool and MutexObjectPool
// init closure used to create an element
// reset closure used to reset element a dropped element
pub fn new<R, I>(init: I, reset: R) -> Self
where
R: Fn(&mut T) + 'static + Send + Sync,
I: Fn() -> T + 'static + Send + Sync + Clone,
{
...
}
// for NoneObjectPool
// init closure used to create an element
pub fn new<I>(init: I) -> Self
where
I: Fn() -> T + 'static
{
...
}
pub fn pull(&self) -> Reusable<T> {
...
}
pub fn pull_owned(self: &Arc<Self>) -> OwnedReusable<T> {
...
}
}
struct Reusable<T> {
}
impl<'a, T> DerefMut for Reusable<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
...
}
}
impl<'a, T> Deref for Reusable<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
...
}
}
struct OwnedReusable<T> {
}
impl<'a, T> DerefMut for OwnedReusable<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
...
}
}
impl<'a, T> Deref for OwnedReusable<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
...
}
}
All implementation support allocation/desallocation from on or more thread. You only need to wrap the pool in a [std::sync::Arc
] :
let pool = Arc::new(LinearObjectPool::<u32>::new(
|| Default::default(),
|v| {*v = 0; }));
Global report.
ObjectPool | Duration in Monothreading (us) | Duration Multithreading (us) |
---|---|---|
NoneObjectPool | 1.2848 | 0.62509 |
MutexObjectPool | 1.3107 | 1.5178 |
SpinLockObjectPool | 1.3106 | 1.3684 |
LinearObjectPool | 0.23732 | 0.38913 |
crate 'sharded-slab' |
1.6264 | 0.82607 |
crate 'object-pool' |
0.77533 | 0.26224 |
Report monothreading and multithreading
ObjectPool | 1 Reader - 1 Writter (ns) | 5 Reader - 1 Writter (ns) | 1 Reader - 5 Writter (ns) | 5 Reader - 5 Writter (ns) |
---|---|---|---|---|
NoneObjectPool | 529.75 | 290.47 | 926.05 | 722.35 |
MutexObjectPool | 429.29 | 207.17 | 909.88 | 409.99 |
SpinLockObjectPool | 34.277 | 182.62 | 1089.7 | 483.81 |
LinearObjectPool | 43.876 | 163.18 | 365.56 | 326.92 |
crate 'sharded-slab' |
525.82 | 775.79 | 966.87 | 1289.2 |
Not supported by crate 'object-pool'
ObjectPool | Duration in Monothreading (ns) | Duration Multithreading (ns) |
---|---|---|
NoneObjectPool | 111.81 | 93.585 |
MutexObjectPool | 26.108 | 101.86 |
SpinLockObjectPool | 22.441 | 50.107 |
LinearObjectPool | 7.5379 | 41.707 |
crate 'sharded-slab' |
7.0394 | 10.283 |
crate 'object-pool' |
20.517 | 44.798 |
Report monothreading and multithreading
crate 'sharded-slab'
: I like pull interface but i dislike
Self
crate 'object-pool'
: use a spinlock to sync and the performance are pretty good but i dislike :
use object_pool::Pool;
let pool = Pool::<Vec<u8>>::new(32, || Vec::with_capacity(4096);
// ...
let item1 = pool.pull(|| Vec::with_capacity(4096));
// ...
let item2 = pool.pull(|| Vec::with_capacity(4096));
crate 'object-pool'
toolsbox
)TODO
crate 'object-pool'
- A thread-safe object pool in rust with mutexcrate 'sharded-slab'
- A lock-free concurrent slabtoolsbox
- Some object pool implementation en c++