プログラムでParallel.ForEachを使用しているときに、一部のスレッドが終了していないように見えることがわかりました。実際、それは新しいスレッドを何度も生成し続けました。これは、私が予期していなかった動作であり、絶対に望まない動作です。
私の「実際の」プログラムと同じように、プロセッサとメモリの両方を多く使用する次のコード(.NET 4.0コード)を使用して、この動作を再現することができました。
public class Node
{
public Node Previous { get; private set; }
public Node(Node previous)
{
Previous = previous;
}
}
public class Program
{
public static void Main(string[] args)
{
DateTime startMoment = DateTime.Now;
int concurrentThreads = 0;
var jobs = Enumerable.Range(0, 2000);
Parallel.ForEach(jobs, delegate(int jobNr)
{
Interlocked.Increment(ref concurrentThreads);
int heavyness = jobNr % 9;
//Give the processor and the garbage collector something to do...
List<Node> nodes = new List<Node>();
Node current = null;
for (int y = 0; y < 1024 * 1024 * heavyness; y++)
{
current = new Node(current);
nodes.Add(current);
}
TimeSpan elapsed = DateTime.Now - startMoment;
int threadsRemaining = Interlocked.Decrement(ref concurrentThreads);
Console.WriteLine("[{0:mm\\:ss}] Job {1,4} complete. {2} threads remaining.", elapsed, jobNr, threadsRemaining);
});
}
}
私のクアッドコアで実行すると、予想どおり、最初は4つの同時スレッドで開始されます。ただし、時間の経過とともに、ますます多くのスレッドが作成されています。最終的に、このプログラムはOutOfMemoryExceptionをスローします。
[00:00] Job 0 complete. 3 threads remaining.
[00:01] Job 1 complete. 4 threads remaining.
[00:01] Job 2 complete. 4 threads remaining.
[00:02] Job 3 complete. 4 threads remaining.
[00:05] Job 9 complete. 5 threads remaining.
[00:05] Job 4 complete. 5 threads remaining.
[00:05] Job 5 complete. 5 threads remaining.
[00:05] Job 10 complete. 5 threads remaining.
[00:08] Job 11 complete. 5 threads remaining.
[00:08] Job 6 complete. 5 threads remaining.
...
[00:55] Job 67 complete. 7 threads remaining.
[00:56] Job 81 complete. 8 threads remaining.
...
[01:54] Job 107 complete. 11 threads remaining.
[02:00] Job 121 complete. 12 threads remaining.
..
[02:55] Job 115 complete. 19 threads remaining.
[03:02] Job 166 complete. 21 threads remaining.
...
[03:41] Job 113 complete. 28 threads remaining.
<OutOfMemoryException>
上記の実験のメモリ使用量グラフは次のとおりです。
(スクリーンショットはオランダ語です。上の部分はプロセッサの使用量、下の部分はメモリの使用量を表しています。)ご覧のとおり、ガベージコレクタが邪魔になるたびに新しいスレッドが生成されているようです(ご覧のとおり) 。メモリ使用量の低下)。
なぜこれが起こっているのか、そして私がそれについて何ができるのかを誰かが説明できますか?.NETで新しいスレッドの生成を停止し、既存のスレッドを最初に終了させたいだけです...