7 个版本
0.1.6 | 2024 年 5 月 19 日 |
---|---|
0.1.5 | 2024 年 1 月 24 日 |
0.1.4 | 2023 年 4 月 10 日 |
0.1.3 | 2021 年 1 月 25 日 |
#33 在 并发
684,855 每月下载量
用于 21 个 Crates (3 直接)
46KB
754 代码行
无锁对象池
一个线程安全的对象池集合,具有自动返回。
某些实现是无锁的
- LinearObjectPool
- SpinLockObjectPool
其他使用 std::Mutex
- MutexObjectPool
和 NoneObjectPool 基本分配,没有池。
用法
[dependencies]
lockfree-object-pool = "0.1"
extern crate lockfree_object_pool;
示例
一般池创建如下
let pool = LinearObjectPool::<u32>::new(
|| Default::default(),
|v| {*v = 0; });
并使用对象池
let mut item = pool.pull();
*item = 5;
...
作用域结束时,项目返回到对象池。
接口
所有实现都支持相同的接口
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 {
...
}
}
多线程
所有实现都支持从一个或多个线程进行分配/释放。您只需要将池包装在 std::sync::Arc
let pool = Arc::new(LinearObjectPool::<u32>::new(
|| Default::default(),
|v| {*v = 0; }));
性能
全局 报告。
分配
ObjectPool | 单线程持续时间 (us) | 多线程持续时间 (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 |
线程间转发消息
ObjectPool | 1 读者 - 1 写者 (ns) | 5 读者 - 1 写者 (ns) | 1 读者 - 5 写者 (ns) | 5 读者 - 5 写者 (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 |
资源释放
ObjectPool | 单线程持续时间(ns) | 多线程持续时间(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 |
与类似库的比较
-
crate 'sharded-slab'
:我喜欢提取接口,但不喜欢- 默认/重置特性,因为它不够灵活
- 性能
- create_owned 方法没有在
Self
上使用引用
-
crate 'object-pool'
:使用自旋锁进行同步,性能相当不错,但我不喜欢- 需要在每次提取时指定回退
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
)
实现细节
待办事项
许可
参考 Boost 许可证
相关项目
crate 'object-pool'
- 使用互斥锁的 Rust 线程安全对象池crate 'sharded-slab'
- 无锁并发块toolsbox
- 一些 C++ 对象池实现