如何在结构中使用可重复使用的Vec 以避免分配?

问题描述 投票:0回答:1

我正在尝试找到在结构中包含Vec<RwLockReadGuard<..>>的方法。该Vec仅在对结构具有独占访问权的函数持续时间内为非空,将其用作可重用Vec以避免每次调用该函数时进行分配。显示错误的最小可复制示例在问题的底部。

动机:我有一个由RwLock保护的数据向量的向量,内部Vec代表被异步修改的数据流。有时,我调用Process::process压缩这些流并使用process_ts函数处理压缩的“ 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

为什么需要使用期限以及由此产生的错误对我来说是显而易见的。但是我想知道是否有一些解决方法,也许是一个将不安全的API提供给不安全的实现的包装箱,这将使我能够做我需要的事情。我想象它只允许从封闭内部访问可重复使用的Vec,以确保在删除封闭之类的东西时清除Vec,我不确定。

我正在尝试找到在结构中包含Vec >的方法。该Vec仅在具有对结构的独占访问权限的函数期间内为非空,将其用作...

rust lifetime
1个回答
0
投票
将其煮沸,似乎您要尝试分配的是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(大小为零但容量不为零);这可能很难正确完成,并且需要根据Vecstd实现的内部细节而定。

© www.soinside.com 2019 - 2024. All rights reserved.