3个版本 (破坏性更新)
0.3.0 | 2021年2月16日 |
---|---|
0.2.0 | 2019年8月17日 |
0.1.0 | 2019年8月17日 |
#1219 in 数据结构
23KB
434 行
swimmer
Rust的线程安全对象池。
use swimmer::Pool;
let pool: Pool<String> = Pool::with_size(10);
assert_eq!(pool.size(), 10);
let value = pool.get()
assert_eq!(pool.size(), 9);
assert_eq!(*value, "");
drop(value);
// Value is returned to pool
assert_eq!(pool.size(), 10);
更多信息请参阅文档。
lib.rs
:
Rust的线程安全对象池。
对象池用于重用对象而不重新分配它们。当从池中请求对象时,它将被取出池外;一旦它被丢弃,它将被返回池中,并可以再次检索。
本软件包的主要类型是Pool
结构体,它实现了一个线程安全对象池。它可以存储实现了Recyclable
特质的对象,该特质允许池初始化和“回收”对象。
其实现如下
- 使用
builder
函数创建一个池。它使用初始大小进行配置。 - 创建池时,池使用
Recyclable
的new
函数初始化initial_size
个值。 - 当从池中请求值时,通常使用
Pool::get()
,从内部缓冲区中取出一个值。如果没有剩余的值,将使用Recyclable::new()
初始化一个新的对象。 - 然后可以由调用者使用该值。
- 当值被丢弃时,它将被返回到池中,并且未来的
Pool::get()
调用可能会返回相同的对象。
为了确保对象被清理,池在将对象返回池之前,会调用对象上的Recyclable::recycle()
。此函数移除了对象的任何已更改状态,实际上“重置”了它。例如,请参阅以下事件序列
- 初始化一个向量池。
- 从池中检索一个向量,并向其中添加一些值。
- 向量被丢弃并返回池中。
在不重置向量的情况下,未来对 Pool::get
的调用可能会返回包含那些旧元素的向量;显然,这不是期望的结果。因此,为 Recyclable
实现的 Vec
在回收时清空向量。
该软件包在很大程度上基于 lifeguard
软件包,但它线程安全,而 lifeguard
不是。
线程安全
Pool
是线程安全的,它可以在线程之间共享或在懒加载的静态变量中使用(请参阅示例)。
目前,这是通过使池为每个线程包含一个线程局部缓冲区来实现的,这已经在基准测试中被证明比使用锁定 Vec
或 crossbeam::SegQueue
高出两倍多。
供应商
在某些情况下,您可能需要指定自己的函数来初始化新对象,而不是使用默认的 Recyclable::new()
函数。在这种情况下,您可以选择使用 PoolBuilder::with_supplier()
,这将使池使用提供的闭包来初始化新值。
例如,对 Recyclable
的实现为 Vec<T>
分配了一个零容量的向量,但您可能想要给向量一个初始容量。在这种情况下,您可以这样做,例如
use swimmer::Pool;
let pool: Pool<Vec<u32>> = swimmer::builder()
.with_supplier(|| Vec::with_capacity(128))
.build();
let vec = pool.get();
assert_eq!(vec.capacity(), 128);
请注意,然而,供应商函数仅在对象首次初始化时被调用:它不会被用于回收对象。这意味着目前没有实现自定义回收功能的方法。
软件包功能
hashbrown-impls
:为hashbrown::HashMap
和hashbrown::HashSet
实现Recyclable
。smallvec-impls
:为SmallVec
实现Recyclable
。
示例
基本用法
use swimmer::Pool;
// Initialize a new pool, allocating
// 10 empty values to start
let pool: Pool<String> = swimmer::builder()
.with_starting_size(10)
.build();
assert_eq!(pool.size(), 10);
let mut string = pool.get();
assert_eq!(*string, ""); // Note that you need to dereference the string, since it is stored in a special smart pointer
string.push_str("test"); // Mutate the string
// One object was taken from the pool,
// so its size is now 9
assert_eq!(pool.size(), 9);
// Now, the string is returned to the pool
drop(string);
assert_eq!(pool.size(), 10);
// Get another string from the pool. This string
// could be the same one retrieved above, but
// since the string is cleared before returning
// into the pool, it is now empty. However, it
// retains any capacity which was allocated,
// which prevents additional allocations
// from occurring.
let another_string = pool.get();
assert_eq!(*another_string, "");
在您的对象上实现 Recyclable
use swimmer::{Pool, Recyclable};
struct Person {
name: String,
age: u32,
}
impl Recyclable for Person {
fn new() -> Self {
Self {
name: String::new(),
age: 0,
}
}
fn recycle(&mut self) {
// You are responsible for ensuring
// that modified `Person`s get reset
// before being returned to the pool.
// Otherwise, the object could be put
// back into the pool with its old state
// still intact; this could cause weird behavior!
self.name.clear();
self.age = 0;
}
}
let pool: Pool<Person> = Pool::new();
let mut josh = pool.get();
josh.name.push_str("Josh"); // Since `recycle` empties the string, this will effectively set `name` to `Josh`
josh.age = 47;
drop(josh); // Josh is returned to the pool and his name and age are reset
// Now get a new person
let another_person = pool.get();
在 lazy_static
变量中使用 Pool
对象,使其可以在全局范围内使用
use lazy_static::lazy_static;
use swimmer::Pool;
lazy_static! {
static ref POOL: Pool<String> = {
Pool::new()
};
}
let value = POOL.get();
依赖项
~43–290KB