次のコードを検討してください。
std::vector<int> indices = /* Non overlapping ranges. */;
std::istream& in = /*...*/;
for(std::size_t i= 0; i< indices.size()-1; ++i)
{
in.seekg(indices[i]);
std::vector<int> data(indices[i+1] - indices[i]);
in.read(reinterpret_cast<char*>(data.data()), data.size()*sizeof(int));
process_data(data);
}
このコードを並列化し、可能な限り高速にしたいと考えています。
PPLを使用してそれを並列化する 1 つの方法は次のとおりです。
std::vector<int> indices = /* Non overlapping ranges. */;
std::istream& in = /*...*/;
std::vector<concurrency::task<void>> tasks;
for(std::size_t i= 0; i< indices.size()-1; ++i)
{
in.seekg(indices[i]);
std::vector<int> data(indices[i+1] - indices[i]);
in.read(reinterpret_cast<char*>(data.data()), data.size()*sizeof(int));
tasks.emplace_back(std::bind(&process_data, std::move(data)));
}
concurrency::when_all(tasks.begin(), tasks.end()).wait();
このアプローチの問題は、メモリに読み取られたのと同じスレッドでデータ (CPU キャッシュに収まる) を処理したい (データがキャッシュ内でホットである) ことですが、ここではそうではありません。ホットデータを使用する機会を無駄にしています。
これを改善する方法が2つありますが、どちらも実現できていません。
別のタスクで次の反復を開始します。
/* ??? */ { in.seekg(indices[i]); std::vector<int> data(indices[i+1] - indices[i]); // data size will fit into CPU cache. in.read(reinterpret_cast<char*>(data.data()), data.size()*sizeof(int)); /* Start a task that begins the next iteration? */ process_data(data); }
メモリ マップされたファイルを使用し、ファイルの必要な領域をマップし、正しいオフセットでポインターから読み取るだけをシークするのではなく。を使用してデータ範囲を処理します
parallel_for_each
。ただし、メモリに読み込まれるタイミングとキャッシュに関する考慮事項に関して、メモリマップファイルのパフォーマンスへの影響を理解していません。ファイルは単純にシステムメモリにDMA:dされ、CPUを通過することはないため、キャッシュを考慮する必要さえないのではないでしょうか?
提案やコメントはありますか?