Parallel.ForEachを使用してさまざまなサイズのPDFを処理しています(数百MBの単純な2MBから高いDPIスキャンまで)、時折OutOfMemoryExceptionになります。プロセスは32ビットであり、Parallel.ForEachによって生成されたスレッドは、未知の量のメモリを消費します。Parallel.ForEachでカスタムTaskSchedulerを使用してOutOfMemoryExceptionを防止する
MaxDegreeOfParallelism
を制限すると動作しますが、小さいPDFファイルの大きな(10k +)バッチがあるときのスループットでは、前記スレッドのメモリフットプリントが小さいために多くのスレッドが動作する可能性があるため十分ではありません。これはParallel.ForEachがCPUの100%CPUに簡単に到達し、大規模なPDFのグループに当たってOutOfMemoryExceptionを取得する前に、重いプロセスです。パフォーマンスプロファイラを実行すると、これがサポートされます。
Parallel.ForEach用のパーティショナーを使用してもパフォーマンスは向上しません。
これは、MemoryFailPoint
小切手で私のParallel.ForEachに渡されたカスタムTaskScheduler
を使用しています。その周辺を検索すると、カスタムのTaskScheduler
オブジェクトの作成に関する不十分な情報があるようです。 StackOverflowの上ここA custom TaskScheduler in C#、Specialized Task Schedulers in .NET 4 Parallel Extensions Extrasの間、様々な答えを探し
は、私のような私のTaskScheduler
を自身と持って、私のQueueTask
メソッドを作成しました:
protected override void QueueTask(Task task)
{
lock (tasks) tasks.AddLast(task);
try
{
using (MemoryFailPoint memFailPoint = new MemoryFailPoint(600))
{
if (runningOrQueuedCount < maxDegreeOfParallelism)
{
runningOrQueuedCount++;
RunTasks();
}
}
}
catch (InsufficientMemoryException e)
{
// somehow return thread to pool?
Console.WriteLine("InsufficientMemoryException");
}
}
のtry/catchは少し高価な私の目標はここですが600MBの可能な最大サイズのPDF(+余分なメモリオーバヘッド)がOutOfMemoryExceptionをスローするときに捕捉することです。この解決策は、InsufficientMemoryExceptionを捕まえたときに作業を試みているスレッドを殺しているようです。十分な大きさのPDFがあれば、私のコードは1つのスレッドParallel.ForEachになります。
-
:Parallel.ForEachとOutOfMemoryExceptionsにStackOverflowの上で見つかった
- Parallel.For System.OutOfMemoryException
- Parallel.ForEach can cause a “Out Of Memory” exception if working with a enumerable with a large object
その他の質問は、スレッドの動的メモリの使用量を最大スループットの私のユースケースに合わせ、多くの場合、単に静的なソリューション、例:としてMaxDegreeOfParallelism
を活用するためには表示されません。だから、変数ワーキングメモリサイズの最大スループットを持つ
、次のいずれか
MemoryFailPoint
チェックで拒否されたスレッドをスレッドプールに戻すにはどうすればよいですか?- 空きメモリがある場合、どのように新しいスレッドを安全に作成して作業を再開するのですか?
編集: ディスク上のPDFのサイズが直線によるPDFコンテンツに依存してラスタライズし、ラスタライズ画像操作コンポーネントにメモリ内のサイズを表していてもよいです。