#对象池 #无锁 #非阻塞 #原子操作

lockfree-object-pool

一个线程安全的对象池集合,具有自动返回和附加/分离语义

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并发

Download history 9870/week @ 2024-04-28 8197/week @ 2024-05-05 8000/week @ 2024-05-12 33747/week @ 2024-05-19 88980/week @ 2024-05-26 120022/week @ 2024-06-02 124774/week @ 2024-06-09 116643/week @ 2024-06-16 112069/week @ 2024-06-23 138818/week @ 2024-06-30 146617/week @ 2024-07-07 154302/week @ 2024-07-14 164872/week @ 2024-07-21 162232/week @ 2024-07-28 166612/week @ 2024-08-04 184507/week @ 2024-08-11

684,855 每月下载量
用于 21 个 Crates (3 直接)

BSL-1.0 许可证

46KB
754 代码行

无锁对象池

License Cargo Documentation CI

一个线程安全的对象池集合,具有自动返回。

某些实现是无锁的

  • 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

不支持 crate 'object-pool'

报告 1-15-11-55-5

资源释放

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 许可证

无运行时依赖