¡¡ Bien !! Después de unos cuantos arreglos, ya tenemos disponible el primer TEST para nuestra plataforma.
Puesto que me gustaría mediante este blog interactuar con las entradas de Stackoverflow, para este primer test he seleccionado este interesante tema: multithreading slower than singlethreading
Y para introducirnos en la filosofía de los TEST, no es mi intención impartir una conferencia sobre este asunto, sino simplemente implementar las casuísticas que nos interesa evaluar, y medir los rendimientos. Vamos a ello.
En primer lugar grabamos en BBDD (a través del recién desarrollado interfaz) el test, y los testcases. La cosa quedaría así:
A nivel programático, debemos definir una clase cuyo nombre se corresponda con el campo "Clase" del Test. Y tantos métodos como "Casos" asociemos al test, haciendo igualmente coincidir los nombres.
En este punto les recuerdo que pueden descargar el proyecto íntegro en EnigmaLABS - GitHub
Para que la comparación de rendimiento de cada una de las técnicas empleadas sea certera, hemos de ejecutar en cada uno de los casos, un mismo problema. Para este caso he pensado en el cálculo de la serie fibonacci, en concreto vamos a calcular 200 elementos de esta serie:
public static void CalcFibo(int numelements) { Dictionary<int, Int64> lstelements = new Dictionary<int, Int64>(); int cont = 0; Int64 anterior = 0; Int64 anterioranterior = 0; while (cont < numelements) { if (cont == 0) { lstelements[cont] = 0; anterioranterior = 0; } else if (cont == 1) { lstelements[cont] = 1; anterior = 1; } else { Int64 newelem = anterioranterior + anterior; anterioranterior = anterior; anterior = newelem; lstelements[cont] = newelem; } cont++; } }
Nota: en próximas publicaciones veremos formas más elegantes de implementar este método.
Vamos a desarrollar tres casos:
1. Cálculo simultáneo de la serie. 500 hilos calcularán cada uno 200 elementos de la serie al unísono.
2. Cálculo secuencial: bucle de 500 iteraciones, en cada una de las cuales calcularemos igualmente 200 elementos de la serie.
3. Híbrido: 20 hilos, cada uno de los cuales calculará 25 veces, 200 elementos de la serie.
¿Adivinan cuál será el resultado?
Antes les dejaré el código de cada uno de los casos, y después le daremos al PLAY para ver los resultados.
CASE 1: Multithreading Case
/// <summary> /// Cálculo simultáneo de la serie fibo (500 hilos, 200 elementos por hilo) /// </summary> /// <param name="_test"></param> /// <returns></returns> public TestCases MultithreadingCase(TestCases _test) { //registra inicio _test.dtBegin = DateTime.Now; SetMsg("- - - - -"); SetMsg("MultithreadingCase iniciado a las " + _test.dtBegin); //500 hilos calculan la serie fibo int cont = 0; while (cont < 500) { Thread thfibo = new Thread(() => CalcFibo1(cont)); _lst_process_control.Add(new objects.process_control() { Estado = objects.process_control.enumEstadoProceso.Ejecutando, Hilo = thfibo }); thfibo.Start(); Thread.Sleep(55); cont++; } while (_lst_process_control.Exists(pc => pc.Estado != objects.process_control.enumEstadoProceso.Finalizado)) { Thread.Sleep(55); } //registra fin _test.dtEnd = DateTime.Now; TimeSpan _ts = _test.dtEnd - _test.dtBegin; SetMsg("MultithreadingCase finalizado a las " + _test.dtEnd); SetMsg("MultithreadingCase ejecutado en " + _ts.TotalMilliseconds + " milisegundos"); _testobject.TestRecord(_test); _lst_process_control.Clear(); return _test; } private static void CalcFibo1(int index) { try { //Console.WriteLine("CalcFibo1 - Index " + index.ToString()); functions.fibo.CalcFibo(200); _lst_process_control[index].Estado = objects.process_control.enumEstadoProceso.Finalizado; } catch (Exception) { _lst_process_control[index].Estado = objects.process_control.enumEstadoProceso.Erroneo; } }
CASE 2: Singlethreading Case
/// <summary> /// Cálculo secuencial de la serie fibo (500 iteraciones, 200 elementos por iteración) /// </summary> /// <param name="_test"></param> /// <returns></returns> public TestCases SinglethreadingCase(TestCases _test) { //registra inicio _test.dtBegin = DateTime.Now; SetMsg("- - - - -"); SetMsg("SinglethreadingCase iniciado a las " + _test.dtBegin); //500 iteraciones calculando 200 elementos de la serie fibo int cont = 0; while (cont < 500) { try { functions.fibo.CalcFibo(200); cont++; Thread.Sleep(55); } catch (Exception) { } } //registra fin _test.dtEnd = DateTime.Now; TimeSpan _ts = _test.dtEnd - _test.dtBegin; SetMsg("SinglethreadingCase finalizado a las " + _test.dtEnd); SetMsg("SinglethreadingCase ejecutado en " + _ts.TotalMilliseconds + " milisegundos"); _testobject.TestRecord(_test); return _test; }
CASE 3: Hybrid Case
public TestCases HybridCase(TestCases _test) { //registra inicio _test.dtBegin = DateTime.Now; SetMsg("- - - - -"); SetMsg("HybridCase iniciado a las " + _test.dtBegin); //20 hilos calculan 25 veces cada uno la serie fibo int cont = 0; while (cont < 50) { Thread thfibo = new Thread(() => CalcFibo2(cont)); _lst_process_control.Add(new objects.process_control() { Estado = objects.process_control.enumEstadoProceso.Ejecutando, Hilo = thfibo }); thfibo.Start(); Thread.Sleep(55); cont++; } while (_lst_process_control.Exists(pc => pc.Estado != objects.process_control.enumEstadoProceso.Finalizado)) { Thread.Sleep(55); } //registra fin _test.dtEnd = DateTime.Now; TimeSpan _ts = _test.dtEnd - _test.dtBegin; SetMsg("HybridCase finalizado a las " + _test.dtEnd); SetMsg("HybridCase ejecutado en " + _ts.TotalMilliseconds + " milisegundos"); _testobject.TestRecord(_test); _lst_process_control.Clear(); return _test; } private static void CalcFibo2(int index) { try { //Console.WriteLine("CalcFibo1 - Index " + index.ToString()); int cont = 0; while (cont < 25) { try { functions.fibo.CalcFibo(200); cont++; Thread.Sleep(55); } catch (Exception) { } } _lst_process_control[index].Estado = objects.process_control.enumEstadoProceso.Finalizado; } catch (Exception) { _lst_process_control[index].Estado = objects.process_control.enumEstadoProceso.Erroneo; } }
Todo listo. Como pueden apreciar la clase va dejando mensajes en una lista que va recogiendo el contenedor para mostrarlos cada N segundos. Estos mensajes dejarán registro del momento de inicio y fin de ejecución de cada caso.
private void SetMsg(string Msg) { this.Mensajes.Add(new test_types.mensajes() { id = Guid.NewGuid(), mensaje = Msg, leido = false }); }
¿Ejecutamos? ¿Sí? ¡Ay qué nervios! Vamos allá, ¡dale al PLAY!
Aquí tienen los esperados resultados. Saquen Uds. sus propias conclusiones:
Por si los resultados se vieran afectados por lo que la máquina este procesando en el momento de la ejecución conviene ejecutarlo varias veces. Hagas Uds. mismos la prueba. Ya les anticipo que los resultados van a ser siempre similares.
Sí cabe la posibilidad que los resultados se vean afectados por las características de la máquina, sobre todo, del procesador o procesadores y núcleos. Esto sería interesante verlo, pero debido a la cuarentena que padecemos no dispongo de medios suficientes. ¿Quieren compartir sus ejecuciones conmigo? ¡No lo duden! Comenten libremente.
Espero les guste la filosofía de los TEST. ¿Quieren proponerme algún desarrollo que poner a prueba? ¿Quieren desarrollar su propia clase? ¡¡No lo duden!! Estaremos encantados de probar soluciones, y más soluciones.
Hasta la próxima amigos.
off topic
ResponderEliminaroff language
off todo
..en todo caso les recomiendo a mis queridos lectores que si necesitan servicios de fumigación en un país árabe-parlante indeterminado no duden en contactar con nuestro amigo ahmed