Acabo de empezar a jugar con la Biblioteca de tareas paralelas, y encontré problemas interesantes; Tengo una idea general de lo que está pasando, pero me gustaría escuchar los comentarios de personas más competentes que yo para ayudar a entender lo que está sucediendo. Mis disculpas por el código algo largo.Bucles paralelos y resultados aleatorios de resultados aleatorios
Empecé con una simulación no paralelos de un paseo aleatorio:
var random = new Random();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var simulations = new List<int>();
for (var run = 0; run < 20; run++)
{
var position = 0;
for (var step = 0; step < 10000000; step++)
{
if (random.Next(0, 2) == 0)
{
position--;
}
else
{
position++;
}
}
Console.WriteLine(string.Format("Terminated run {0} at position {1}.", run, position));
simulations.Add(position);
}
Console.WriteLine(string.Format("Average position: {0} .", simulations.Average()));
stopwatch.Stop();
Console.WriteLine(string.Format("Time elapsed: {0}", stopwatch.ElapsedMilliseconds));
Console.ReadLine();
Entonces escribí mi primer intento de un circuito paralelo:
var localRandom = new Random();
stopwatch.Reset();
stopwatch.Start();
var parallelSimulations = new List<int>();
Parallel.For(0, 20, run =>
{
var position = 0;
for (var step = 0; step < 10000000; step++)
{
if (localRandom.Next(0, 2) == 0)
{
position--;
}
else
{
position++;
}
}
Console.WriteLine(string.Format("Terminated run {0} at position {1}.", run, position));
parallelSimulations.Add(position);
});
Console.WriteLine(string.Format("Average position: {0} .", parallelSimulations.Average()));
stopwatch.Stop();
Console.WriteLine(string.Format("Time elapsed: {0}", stopwatch.ElapsedMilliseconds));
Console.ReadLine();
Cuando me encontré con él en una máquina virtual configurado para usar solo 1 núcleo, observé una duración similar, pero las ejecuciones ya no se procesan en orden, no es una sorpresa.
Cuando lo ejecuté en una máquina de doble núcleo, las cosas salieron raras. No vi ninguna mejora en el tiempo, y observé algunos resultados muy extraños para cada carrera. La mayoría de las ejecuciones terminan con resultados de -1,000,000, (o muy cercanos), lo que indica que Random.Next está regresando 0 casi todo el tiempo.
Cuando hago el azar local para cada bucle, todo funciona muy bien, y tengo la mejora de la duración esperada:
Parallel.For(0, 20, run =>
{
var localRandom = new Random();
var position = 0;
Mi conjetura es que el problema tiene que ver con el hecho de que el objeto aleatorio se comparte entre los bucles, y tiene algún estado. La falta de mejora en la duración en la versión "paralela fallida" es de suponer que las llamadas a Random no se procesan en paralelo (aunque veo que la versión paralela usa ambos núcleos, mientras que el original no) . La pieza que realmente no entiendo es por qué los resultados de la simulación son lo que son.
Una preocupación aparte que tengo es que si uso instancias aleatorias locales para cada ciclo, puedo encontrarme con el problema de tener múltiples bucles comenzando con la misma inicialización (el problema que surge cuando genera múltiples Randoms demasiado cerca en el tiempo) , dando como resultado secuencias idénticas).
¡Cualquier idea sobre lo que está pasando sería muy valiosa para mí!
Ade, gracias por el puntero al artículo de S. Toub, es excelente. – Mathias