【发布时间】:2019-09-12 09:46:24
【问题描述】:
我正在缓冲一个进程的 stdout、stderr 和 stdin 的最后 X 行。 我想保留最后 X 行,并能够通过其 id(行号)访问一行。 因此,如果我们存储 100 行并插入其中 200 行,则可以访问第 100-200 行。 (实际上我们想要存储大约 2000 行。)
性能案例是插入。所以插入本身应该很快。检索偶尔会发生,但可能占用例的 10%。 (大部分时间我们不会查看输出。)
旧方法,碎片化
我使用了包装 ArrayDeque,然后将 book 保留在行数之上,但这意味着我们在上面的示例中使用了 [Vec<u8>;100]。一个 String 数组,因此是一个 Vec<u8> 数组。
新方法,有开放性问题
我*的新想法是将数据存储在一个 u8 数组中,然后将 book 保存在数组中每个条目的起始位置和长度上。这里的问题是我们需要簿记也是某种环形缓冲区,并在我们的数据数组必须包装的那一刻擦除旧条目。也许还有更好的方法来实现这一点?至少这充分利用了环形缓冲区并防止了内存碎片。
*也感谢 rust 社区的 sebk
目前的简单方法
const MAX: usize = 5;
pub struct LineRingBuffer {
counter: Option<usize>,
data: ArrayDeque<[String; MAX], Wrapping>,
min_line: usize,
}
impl LineRingBuffer {
pub fn new() -> Self {
Self {
counter: None,
data: ArrayDeque::new(),
min_line: 0,
}
}
pub fn get<'a>(&'a self,pos: usize) -> Option<&String> {
if let Some(max) = self.counter {
if pos >= self.min_line && pos <= max {
return self.data.get(pos - self.min_line);
}
}
None
}
pub fn insert(&mut self, line: String) {
self.data.push_back(line);
if let Some(ref mut v) = self.counter {
*v += 1;
if *v - self.min_line >= MAX {
self.min_line += 1;
}
} else {
self.counter = Some(0);
}
}
}
被质疑的新想法草案:
pub struct SliceRingbuffer {
counter: Option<usize>,
min_line: usize,
data: Box<[u8;250_000]>,
index: ArrayDeque<Entry,Wrapping>,
}
struct Entry {
start: usize,
length: usize,
}
无论出于何种原因,当前的方法仍然相当快,尽管我预计会有很多不同大小的分配(取决于行)并因此产生碎片。
【问题讨论】:
标签: data-structures rust circular-buffer