1 个不稳定版本
0.1.0 | 2024 年 4 月 29 日 |
---|
在 并发 中排名 #307
每月下载量:177
11KB
53 行
dropout
一个小型库,用于将您的值发送到线程以进行丢弃。受 Aaron Abramov 的文章这篇文章和defer-drop crate的启发
简单示例
// See examples/demo.rs
type HeavyObject = HashMap<usize, Vec<usize>>;
fn make_heavy_object() -> HeavyObject {
(1..=NUM_ELEMENTS).map(|v| (v, vec![v])).collect()
}
println!("Allocating a heavy object");
let first_heavy_object = make_heavy_object();
println!("Duplicating that vector");
let second_heavy_object = first_heavy_object.clone();
// Create a dropper, dropping `Vec<Vec<String>>`.
let dropper = dropout::new_dropper();
// This is a special case for this small test.
// The closure will explictly drop vec1 but also implicitly drop the `dropper`
// and we don't want that as, at drop, dropper wait for background thread.
// We don't want to mesure that.
let dropper_clone = dropper.clone();
let dropout_timer = timer(move || dropper_clone.dropout(first_heavy_object));
let std_timer = timer(move || drop(second_heavy_object));
println!("Duration of dropout: {:?}", dropout_timer);
println!("Duration of std drop: {:?}", std_timer);
输出结果(可能是)
Allocating a heavy object
Duplicating that vector
Dropping the vectors
Duration of dropout: 7.479µs
Duration of std drop: 50.864814ms
与 defer-drop 的区别
API
Defer-drop 使用一个全局的后台线程来丢弃任何类型。
- 所有值都通过
Box
发送到后台线程。 - 您必须创建一个
DeferDrop
,它将包装您的值,并在包装器被丢弃时将其发送到丢弃线程。
Dropout 的相反方向
- 您创建一个 Dropper,它接受(并获取所有权)一个
T
。 - 您有一个线程对应一个 Dropper。
- 您处理
T
对象,并在结束时显式延迟丢弃。
因此,您操作的是 T
值,而不是 Box<Self>
。但您必须明确关于丢弃值。
保证
Defer-drop 不保证值实际上被丢弃,因为主线程可能先于丢弃线程完成所有值的丢弃。 Dropper
等待(因此,在丢弃时阻塞)后台线程完成(并丢弃所有值)之前才会被丢弃。
许可差异
- defer-drop 根据 MPL-2.0 许可
- dropout 根据 MIT 许可
// In external library
pub trait MyTrait {
fn get_u32(&self) -> u32;
}
fn do_stuff_with_object<T: MyTrait>(object: T) {
...
drop(object)
}
// In user library
use external_library::{MyTrait, do_stuff_with_object};
struct MyObject {}
impl MyTrait for MyObject {
fn get_u32(self) -> u32 {
5
}
};
struct DeferedMyObject(DeferedDrop<MyObject>)
impl MyTrait for DeferedMyObject {
fn get_u32(&self) -> u32 {
self.0.get_u32()
}
}
fn main() {
do_stuff_with_object(MyObject{}); // Works
do_stuff_with_object(DeferDrop::new(MyObject{})); // Doesn't work as DeferDrop doesn't impl MyTrait
do_stuff_with_object(DeferedMyObject(DeferDrop::new(MyObject{}))); // Works
}
如果 trait 使用 Box<Self>
消费自身,则几乎不可能做到这一点
pub trait MyTrait {
fn get_as_u32(self: Box<Self>) -> u32;
}
fn do_stuff_with_u32(object: Box<dyn MyTrait>) {
let value = object.get_as_u32();
...
}
注意
Dropout(类似于 defer-drop)不是万能的。将值发送到另一个线程是昂贵的,并且可能适得其反。在使用此类 crate 之前,请始终进行性能分析。
丢弃的值被排队到一个无界通道中,以便由丢弃线程消费;如果您产生的值多于线程可以处理的值,这会导致无界内存消耗。目前没有方法让线程在过载时发出信号或阻塞。
所有标准非确定性线程注意事项都适用。对象保证按接收的顺序在通道中进行解构,这意味着来自单个线程的对象将按顺序解构。然而,无法保证来自不同线程的交错值的顺序。
此外,无法保证值在丢弃前将被排队多长时间。然而,当丢弃器被丢弃时,它将等待后台线程完成,因此可以保证所有对象最终都会被丢弃。
依赖项
~345KB