【发布时间】:2016-08-22 09:34:05
【问题描述】:
我正在尝试将大的HashMap<K, V> 转换为Vec<(K, V)>。通常的做法是这样的:
// initialize HashMap
let cap = 50000000;
let mut hm: HashMap<usize, usize> = HashMap::new();
for i in 0..cap {
hm.insert(i, i);
}
// convert HashMap to Vec
let vec = hm.into_iter().collect::<Vec<(usize, usize)>>();
如果HashMap 足够大,此代码将无法正常工作 - 在对collect() 的调用开始时,原始HashMap 仍将在内存中,Vec 将分配较低的容量大小提示取自 Iterator。这会导致非常大的HashMaps 出现内存不足的恐慌,即使我应该能够在这两种类型之间进行转换,而且只需要很少的额外内存开销。到目前为止,我想出了以下解决方案:
// create small vector
let mut vec: Vec<(usize, usize)> = Vec::with_capacity(100);
for i in hm.into_iter() {
vec.push(i);
// reserve few megabytes
if vec.capacity() - vec.len() < 10 {
vec.reserve_exact(1000000);
}
}
有没有更好(更有效或更惯用)的方法来解决这个问题?如果要提高性能,我愿意使用unsafe 代码。
编辑
正如所指出的into_iter 在迭代期间不会释放,因此建议的解决方案无法按预期工作。除了将HashMap 转储到文件然后将该文件读入Vec 之外,还有其他方法可以转换这些集合吗?
【问题讨论】:
-
你确定你的第二个代码有更少的内存开销吗?我认为
IntoIter迭代器不会在迭代期间释放内存。实际上,用很少的额外内存来进行这个对话并不容易...... -
如果没有足够的内存来同时存储
HashMap和Vec,您可能需要切换计算机,或者重组您的程序以便能够处理更小的块工作量(例如 MapReduce)。事实上,您的空间非常小:如果问题规模增加 50%,您很可能会因为 仅HashMap而出现 OOM,然后您将怎么做?跨度>
标签: performance memory-management collections rust out-of-memory