Estoy intentando descubrir cómo usar correctamente los ejecutores de Java. Me doy cuenta de que enviar tareas a un ExecutorService
tiene su propia sobrecarga. Sin embargo, me sorprende ver que es tan alto como lo es.El sorprendente punto de equilibrio de rendimiento del ExecutorService --- ¿reglas de oro?
Mi programa necesita procesar gran cantidad de datos (datos bursátiles) con la latencia más baja posible. La mayoría de los cálculos son operaciones aritméticas bastante simples.
Me trataron de probar algo muy simple: "Math.random() * Math.random()
"
La prueba más simple se ejecuta este cálculo en un bucle simple. La segunda prueba realiza el mismo cálculo dentro de Runnable anónimo (se supone que esto mide el costo de crear objetos nuevos). La tercera prueba pasa el Runnable
a ExecutorService
(esto mide el costo de introducir ejecutores).
me corrieron las pruebas en mi portátil pequeño (2 CPUs, 1,5 concierto RAM):
(in milliseconds)
simpleCompuation:47
computationWithObjCreation:62
computationWithObjCreationAndExecutors:422
(aproximadamente una vez cada cuatro carreras, los dos primeros números terminan siendo iguales)
Aviso que los ejecutores toman mucho, mucho más tiempo que ejecutando en un solo hilo. Los números eran aproximadamente los mismos para los tamaños de grupo de subprocesos entre 1 y 8.
Pregunta: ¿Me falta algo obvio o se esperan estos resultados? Estos resultados me dicen que cualquier tarea que paso a un ejecutor debe hacer un cálculo no trivial. Si estoy procesando millones de mensajes y necesito realizar transformaciones muy simples (y baratas) en cada mensaje, aún no puedo usar ejecutores ... tratar de distribuir cálculos entre múltiples CPU podría terminar siendo más costoso que solo haciéndolos en un solo hilo. La decisión de diseño se vuelve mucho más compleja de lo que originalmente pensé. ¿Alguna idea?
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ExecServicePerformance {
private static int count = 100000;
public static void main(String[] args) throws InterruptedException {
//warmup
simpleCompuation();
computationWithObjCreation();
computationWithObjCreationAndExecutors();
long start = System.currentTimeMillis();
simpleCompuation();
long stop = System.currentTimeMillis();
System.out.println("simpleCompuation:"+(stop-start));
start = System.currentTimeMillis();
computationWithObjCreation();
stop = System.currentTimeMillis();
System.out.println("computationWithObjCreation:"+(stop-start));
start = System.currentTimeMillis();
computationWithObjCreationAndExecutors();
stop = System.currentTimeMillis();
System.out.println("computationWithObjCreationAndExecutors:"+(stop-start));
}
private static void computationWithObjCreation() {
for(int i=0;i<count;i++){
new Runnable(){
@Override
public void run() {
double x = Math.random()*Math.random();
}
}.run();
}
}
private static void simpleCompuation() {
for(int i=0;i<count;i++){
double x = Math.random()*Math.random();
}
}
private static void computationWithObjCreationAndExecutors()
throws InterruptedException {
ExecutorService es = Executors.newFixedThreadPool(1);
for(int i=0;i<count;i++){
es.submit(new Runnable() {
@Override
public void run() {
double x = Math.random()*Math.random();
}
});
}
es.shutdown();
es.awaitTermination(10, TimeUnit.SECONDS);
}
}
Wow, la vista previa formateó el código mucho mejor que el resultado final. ¿Cómo puedo arreglar esto? – Shahbaz
Acabo de reformatearlo, ¿se ve mejor? –
Gracias ZZ Coder, el código ahora parece que debería – Shahbaz