我的算法使用Vec<RwLockReadGuard<..>>
处理数据。该算法被重复调用,并且我不想每次都被分配Vec
,如果可以在处理结束时对其进行clear()
并将其存储在与数据处理相关的相同结构。但是,RwLockReadGuard
的生存期短于保持结构的可能生存期。由于我只在数据处理函数内部使用Vec
,而在它外部始终为空,因此我仍可以某种方式将其存储在struct中吗?是否有 crate 或成语可能会对我有所帮助?
显示问题的最小可重现示例位于问题的底部。
如果每次都分配Vec
,它将是这样的:
#[derive(Clone)]
pub struct T;
pub fn process_ts(ts: &[T]) {
unimplemented!();
}
struct Process {
locked_ts: Vec<RwLock<Vec<T>>>,
}
impl Process {
pub fn process(&self) {
let mut ts: Vec<T> = Vec::with_capacity(self.locked_ts.len());
let guards: Vec<RwLockReadGuard<Vec<T>>> = self
.locked_ts
.iter()
.map(|locked_t| locked_t.read().unwrap())
.collect();
let n = guards.iter().map(|guard| guard.len()).min().unwrap();
for i in 0..n {
ts.clear();
for t in &guards {
ts.push(t[i].clone());
process_ts(&ts);
}
}
}
}
我对这种解决方案不满意的是,每次调用
Process::process
时,都会分配ts: Vec<T>
和guards: Vec<RwLockReadGuard<Vec<T>>>
。我可以摆脱ts
:struct ProcessReuseTs {
locked_ts: Vec<RwLock<Vec<T>>>,
reusable_ts: Vec<T>,
}
impl ProcessReuseTs {
pub fn process(&mut self) {
let guards: Vec<RwLockReadGuard<Vec<T>>> = self
.locked_ts
.iter()
.map(|locked_t| locked_t.read().unwrap())
.collect();
let n = guards.iter().map(|guard| guard.len()).min().unwrap();
for i in 0..n {
self.reusable_ts.clear();
for t in &guards {
self.reusable_ts.push(t[i].clone());
process_ts(&self.reusable_ts);
}
}
}
}
但是,如何提取
guards
呢?use std::sync::{RwLock, RwLockReadGuard};
#[derive(Clone)]
pub struct T;
pub fn process_ts(ts: &[T]) {
unimplemented!();
}
struct ProcessReuseBoth {
locked_ts: Vec<RwLock<Vec<T>>>,
reusable_ts: Vec<T>,
reusable_guards: Vec<RwLockReadGuard<Vec<T>>>,
}
impl ProcessReuseBoth {
pub fn process(&mut self) {
self.reusable_guards.clear();
self.reusable_guards.extend(
self.locked_ts
.iter()
.map(|locked_t| locked_t.read().unwrap()),
);
let n = self
.reusable_guards
.iter()
.map(|guard| guard.len())
.min()
.unwrap();
for i in 0..n {
self.reusable_ts.clear();
for t in &self.reusable_guards {
self.reusable_ts.push(t[i].clone());
process_ts(&self.reusable_ts);
}
}
self.reusable_guards.clear();
}
}
pub fn main() {
unimplemented!()
}
不与
error[E0106]: missing lifetime specifier
--> src/main.rs:13:26
|
13 | reusable_guards: Vec<RwLockReadGuard<Vec<T>>>,
|
Playground
最佳答案
归根结底,似乎您想要做的是分配一个Vec
。使用它来存储某些生命周期RwLockReadGuard<'a, Vec<T>>
的'a
类型的元素,然后清除向量并将其放入RwLockReadGuard<'b, Vec<T>>
类型的元素,其中生命周期'b
是与'a
不同的生命周期(实际上没有重叠),依此类推。这是行不通的,因为RwLockReadGuard<'a, Vec<T>>
是与RwLockReadGuard<'b, Vec<T>>
不同的类型,并且我们无法更改Vec
所保存的元素的类型。
但是也许真正的目标不是用相同的Vec
来保存这些不同类型的元素(这是不可能的),而是只是避免需要重新分配每个新的Vec
。我们可能会问,是否可以从旧的Vec
中回收已分配的内存,从而跳过不必分配下一个Vec
的情况?好吧,对于一些非常丑陋,不安全的代码,可能有可能只分配一个Vec<u8>
,然后在每次调用process
时都要进行一些指针争夺,以将其就地转换为所需类型的Vec
(大小为零,但非零)。零容量);这可能很难正确完成,并且需要根据Vec
中std
实现的内部细节进行操作。
也许值得退后一步,认识到每次在堆上分配内容时我们都可以问同样的问题-也就是说,是否有一种方法可以重用刚释放的内容中的空间,从而避免执行新操作分配?在某些情况下,答案可能是肯定的,但是我们不得不问一下,是否值得将我们的代码弄乱以进行优化?
这就引出了一个问题-我们是否有任何证据表明这里的分配实际上是一个重要的性能瓶颈?如果没有,也许就不用担心了。如果确实需要提高分配性能,则可以尝试使用jemalloc
或某种形式的竞技场。
关于rust - 如何在结构中具有可重用的Vec <RwLockReadGuard>以避免分配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62330718/