大きな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
から取られたより小さいサイズのヒントの容量で割り当てられます。これにより、メモリオーバーヘッドがほとんどなく、これらの2つのタイプ間で変換できるはずですが、実際には大きなメモリ不足が発生します(HashMap
)。これまでのところ私は、次の解決策を考え出したています
// 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
に読み込む方法はありますか?
2番目のコードのメモリオーバーヘッドは少ないですか?私は 'IntoIter'イテレータが反復中にメモリを解放するとは思わない。実際には、小さなメモリを追加してこの会話をするのは簡単ではありません。 –
'HashMap'と' Vec'を同時に保存するのに十分なメモリがない場合は、コンピュータを切り替えるか、小さな仕事の作業(MapReduceなど)で作業できるようにプログラムを再構築します。つまり、問題のサイズが50%増加すると、「HashMap」だけでOOMになる可能性があります。次に何をするつもりですか? –