ventajas solo sistema simétrico presenta por paralelo operativo multiproceso multiprocesamiento multiprocesadores multiprocesador ejemplos desventajas conectados asimétrico asimetrico asimetria ante c# multithreading performance mono multiprocessing

c# - solo - Problema de rendimiento mono multiprocesamiento



sistema operativo multiprocesador ejemplos (1)

Correr con mono --gc=sgen me lo arregló, como era de esperar (usando Mono 3.0.10).

El problema subyacente es que la asignación local de subprocesos para el recopilador de basura Boehm requiere un ajuste especial cuando se utiliza junto con una asignación tipada o bloques grandes. Esto no solo es algo trivial sino que también tiene algunas desventajas: o hace que el marcado sea más complicado / costoso o necesita una libreta por hilo y tipo (bueno, por diseño de memoria).

Por lo tanto, de manera predeterminada, Boehm GC solo admite áreas de memoria completamente sin puntero o áreas donde cada palabra puede ser un puntero, hasta un máximo de 256 bytes más o menos.

Pero sin asignación local de subprocesos, cada asignación adquiere un bloqueo global, que se convierte en un cuello de botella.

El recolector de basura SGen está escrito a medida para Mono, específicamente diseñado para trabajar rápido en un sistema multihebra, y no presenta estos problemas.

Tengo problemas graves de rendimiento cuando ejecuto código multiprocesado con gran cantidad de cómputo en Mono. El siguiente fragmento simple, que estima el valor de pi utilizando métodos de Monte Carlo, demuestra el problema.

El programa engendra una cantidad de hilos igual al número de núcleos lógicos en la máquina actual, y realiza un cálculo idéntico en cada uno. Cuando se ejecuta en una computadora portátil Intel Core i7 con Windows 7 utilizando .NET Framework 4.5, todo el proceso se ejecuta en 4.2 s, y la desviación estándar relativa entre los tiempos de ejecución respectivos de los hilos es del 2%.

Sin embargo, cuando se ejecuta en la misma máquina (y sistema operativo) utilizando Mono 2.10.9, el tiempo total de ejecución se dispara hasta 18 s. Hay una gran variación entre los rendimientos de los respectivos hilos, con el más rápido completando en solo 5.6 s, mientras que el más lento tarda 18 s. El promedio es 14 s, y la desviación estándar relativa es 28%.

La causa no parece ser la programación de hilos. Fijar cada subproceso en un núcleo distinto (llamando a BeginThreadAffinity y SetThreadAffinityMask ) no tiene ningún efecto significativo en las duraciones o variaciones de los subprocesos.

Del mismo modo, ejecutar el cálculo en cada hilo varias veces (y cronometrarlas individualmente) también da duraciones aparentemente ad hoc. Por lo tanto, el problema no parece ser causado por los tiempos de calentamiento por procesador tampoco.

Lo que encontré para marcar la diferencia fue fijar los 8 hilos en el mismo procesador. En este caso, la ejecución general fue de 25 s, que es solo un 1% más lenta que la ejecución de 8 × el trabajo en un solo hilo. Además, la desviación estándar relativa también se redujo a menos del 1%. Por lo tanto, el problema no radica en el multihilo de Mono per se, sino en su multiprocesamiento.

¿Alguien tiene una solución sobre cómo solucionar este problema de rendimiento?

static long limit = 1L << 26; static long[] results; static TimeSpan[] timesTaken; internal static void Main(string[] args) { int processorCount = Environment.ProcessorCount; Console.WriteLine("Thread count: " + processorCount); Console.WriteLine("Number of points per thread: " + limit.ToString("N0")); Thread[] threads = new Thread[processorCount]; results = new long[processorCount]; timesTaken = new TimeSpan[processorCount]; for (int i = 0; i < processorCount; ++i) threads[i] = new Thread(ComputeMonteCarloPi); Stopwatch stopwatch = Stopwatch.StartNew(); for (int i = 0; i < processorCount; ++i) threads[i].Start(i); for (int i = 0; i < processorCount; ++i) threads[i].Join(); stopwatch.Stop(); double average = results.Average(); double ratio = average / limit; double pi = ratio * 4; Console.WriteLine("Pi: " + pi); Console.WriteLine("Overall duration: " + FormatTime(stopwatch.Elapsed)); Console.WriteLine(); for (int i = 0; i < processorCount; ++i) Console.WriteLine("Thread " + i.ToString().PadLeft(2, ''0'') + " duration: " + FormatTime(timesTaken[i])); Console.ReadKey(); } static void ComputeMonteCarloPi(object o) { int processorID = (int)o; Random random = new Random(0); Stopwatch stopwatch = Stopwatch.StartNew(); long hits = SamplePoints(random); stopwatch.Stop(); timesTaken[processorID] = stopwatch.Elapsed; results[processorID] = hits; } private static long SamplePoints(Random random) { long hits = 0; for (long i = 0; i < limit; ++i) { double x = random.NextDouble() - 0.5; double y = random.NextDouble() - 0.5; if (x * x + y * y <= 0.25) hits++; } return hits; } static string FormatTime(TimeSpan time, int padLeft = 7) { return time.TotalMilliseconds.ToString("N0").PadLeft(padLeft); }

Salida en .NET:

Thread count: 8 Number of points per thread: 67,108,864 Pi: 3.14145541191101 Overall duration: 4,234 Thread 00 duration: 4,199 Thread 01 duration: 3,987 Thread 02 duration: 4,002 Thread 03 duration: 4,032 Thread 04 duration: 3,956 Thread 05 duration: 3,980 Thread 06 duration: 4,036 Thread 07 duration: 4,160

Salida en Mono:

Thread count: 8 Number of points per thread: 67,108,864 Pi: 3.14139330387115 Overall duration: 17,890 Thread 00 duration: 10,023 Thread 01 duration: 13,203 Thread 02 duration: 14,776 Thread 03 duration: 15,564 Thread 04 duration: 17,888 Thread 05 duration: 16,776 Thread 06 duration: 16,050 Thread 07 duration: 5,561

Salida en Mono, con todos los hilos anclados al mismo procesador:

Thread count: 8 Number of points per thread: 67,108,864 Pi: 3.14139330387115 Overall duration: 25,260 Thread 00 duration: 24,704 Thread 01 duration: 25,191 Thread 02 duration: 24,689 Thread 03 duration: 24,697 Thread 04 duration: 24,716 Thread 05 duration: 24,725 Thread 06 duration: 24,707 Thread 07 duration: 24,720

Salida en Mono, single thread:

Thread count: 1 Number of points per thread: 536,870,912 Pi: 3.14153660088778 Overall duration: 25,090