我試圖將大HashMap<K, V>
轉換爲Vec<(K, V)>
。這樣做的通常的方式是這樣的:HashMap和Vec之間的內存高效轉換
// 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
中分配了較小尺寸提示的容量。這會導致內存不足,造成真正大的HashMap
s,儘管我應該可以在這兩種類型之間進行轉換,而只需很少的額外內存開銷。
// 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,那麼你打算怎麼做? –