Mentre utilizzavo Parallel.ForEach nel mio programma, ho trovato che alcuni thread non sembravano mai finire. In effetti, continuava a generare nuovi thread più e più volte, un comportamento che non mi aspettavo e sicuramente non volevo.Parallel.ForEach continua a generare nuovi thread
sono stato in grado di riprodurre questo comportamento con il seguente codice, che, proprio come il mio programma 'reale', entrambi gli usi processore e la memoria molto (NET 4.0 codice):
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);
});
}
}
Quando viene eseguito sul mio quad-core, inizia inizialmente con 4 thread simultanei, proprio come ci si aspetterebbe. Tuttavia, nel tempo vengono creati sempre più thread. Alla fine, questo programma quindi genera un 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>
Il grafico utilizzo della memoria per l'esperimento di cui sopra è il seguente:
(L'immagine è in Olandese, la parte superiore rappresenta processore utilizzo, l'utilizzo della memoria della parte inferiore.) Come si può vedere, sembra che un nuovo thread venga generato quasi ogni volta che il garbage collector si mette in mezzo (come si può vedere negli intervalli di utilizzo della memoria).
Qualcuno può spiegare perché questo sta accadendo e cosa posso fare al riguardo? Voglio solo .NET per fermare la deposizione delle uova nuove discussioni, e finire i thread esistenti prima ...
ho girato una domanda di follow-up [ ] (http://stackoverflow.com/questions/15381174/how-to-count-the-amount-of-concurrent-threads-in-net-application) Se per i thread direttamente, c sono per lo più in aumento (molto raramente e in modo insignificante decrescente) – Fulproof