¿Por qué un solo hilo es más rápido que multihilo en Java?

Según tengo entendido, he escrito el sencillo progtwig simple y de subprocesamiento múltiple a continuación para verificar la velocidad de ejecución. Pero mi progtwig de subproceso único se ejecuta más rápido que multiproceso, amablemente vea el siguiente progtwig y mencione si algo está mal.

Single Thread:

import java.util.Calendar; public class NormalJava { public static void main(String[] args) { System.out.println("Single Thread"); int a = 1000; int b = 200; NormalJava nj = new NormalJava(); nj.Add(a, b); nj.Sub(a, b); nj.Mul(a, b); nj.Div(a, b); Calendar lCDateTime = Calendar.getInstance(); System.out.println("Calender - Time in milliseconds :" + lCDateTime.getTimeInMillis()); } private void Add(int a, int b) { System.out.println("Add :::" + (a + b)); } private void Sub(int a, int b) { System.out.println("Sub :::" + (a - b)); } private void Mul(int a, int b) { System.out.println("Mul :::" + (a * b)); } private void Div(int a, int b) { System.out.println("Mul :::" + (a / b)); } } 

Salida:
Single Thread
Añadir ::: 1200
Sub ::: 800
Mul ::: 200000
Mul ::: 5
Calendario: tiempo en milisegundos: 138 415 866 7863

Progtwig multiproceso:

 package runnableandcallable; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class MainThread { private static ExecutorService service = Executors.newFixedThreadPool(10); // connection // pool @SuppressWarnings("unchecked") public static void main(String[] args) throws InterruptedException { System.out.println("Multithreading"); MainThread mt = new MainThread(); mt.testThread(1000, 200); Calendar lCDateTime = Calendar.getInstance(); System.out.println("Calender - Time in milliseconds :" + lCDateTime.getTimeInMillis()); } public void testThread(final int a, final int b) { // create a callable for each method Callable callableAdd = new Callable() { @Override public Void call() throws Exception { Add(a, b); return null; } }; Callable callableSub = new Callable() { @Override public Void call() throws Exception { Sub(a, b); return null; } }; Callable callableMul = new Callable() { @Override public Void call() throws Exception { Mul(a, b); return null; } }; Callable callableDiv = new Callable() { @Override public Void call() throws Exception { Div(a, b); return null; } }; // add to a list List<Callable> taskList = new ArrayList<Callable>(); taskList.add(callableAdd); taskList.add(callableSub); taskList.add(callableMul); taskList.add(callableDiv); // create a pool executor with 3 threads ExecutorService executor = Executors.newFixedThreadPool(3); try { // start the threads List<Future> futureList = executor.invokeAll(taskList); for (Future voidFuture : futureList) { try { // check the status of each future. get will block until the // task // completes or the time expires voidFuture.get(100, TimeUnit.MILLISECONDS); } catch (ExecutionException e) { System.err .println("Error executing task " + e.getMessage()); } catch (TimeoutException e) { System.err.println("Timed out executing task" + e.getMessage()); } } } catch (InterruptedException ie) { // do something if you care about interruption; } } private void Add(int a, int b) { System.out.println("Add :::" + (a + b)); } private void Sub(int a, int b) { System.out.println("Sub :::" + (a - b)); } private void Mul(int a, int b) { System.out.println("Multiply :::" + (a * b)); } private void Div(int a, int b) { System.out.println("Division :::" + (a / b)); } } 

Salida Mulithreading:
Multihilo
Sub ::: 800
División ::: 5
Añadir ::: 1200
Multiplicar ::: 200000
Calendario: tiempo en milisegundos: 138 415 868 0821

Aquí, el hilo único se ejecutó a 138 415 866 7863 milisegundos y el multihilo se ejecutó en este 138 415 868 0821 milisegundos. Entonces, ¿cuál es el verdadero propósito de multihilo?

El procesamiento que estás haciendo es trivial, por lo que la sobrecarga de crear subprocesos es más costosa.

Si tenía operaciones costosas que podrían realizarse en paralelo, entonces los subprocesos múltiples tienen sentido.

Primero : porque la sobrecarga de crear subprocesos más que el trabajo útil que realizan. Si ejecuta más trabajo arduo en subprocesos, lo hará más rápido que un subproceso. El código trivial debe ejecutarse en un subproceso.

Segundo : para crear una micro-referencia, debes usar JMH

1,384,158,667,863 milisegundos tienen aproximadamente 44 años. Entonces, ¿nos está diciendo que esperó 44 años el resultado de esta operación? ¿O podría haber algo mal con la forma en que estás midiendo la velocidad de la ejecución?

Para medir la diferencia entre dos veces, necesita al menos dos veces, mientras que solo obtiene la fecha actual al final de su progtwig, que ni siquiera está cerca de ser precisa.

Clase de medición de tiempo simple:

 public class StopWatch { private long startTime = -1; public void start() { this.startTime = System.nanoTime(); } public long timeNanos() { return System.nanoTime() - this.startTime; } public double timeMillis() { return this.timeNanos() / 1000000.0; } } 

Use este cronómetro para medir el tiempo de ejecución (como si fuera un cronómetro), luego hágalo 3 veces y descubra que cada vez obtiene resultados completamente diferentes. Esto se debe a que medir el tiempo de ejecución exacto no es para nada trivial. El sistema operativo interrumpe constantemente la ejecución de su progtwig con otras tareas y los comandos aparentemente simples pueden tener toda una cadena de comandos de fondo que deben ejecutarse.

Todo lo que puede hacer es aproximarse al tiempo que lleva ejecutar esa tarea como un millón de veces y luego tomar el promedio.

Antes que nada, tu tiempo en milisegundos es solo la marca de tiempo. Necesita la diferencia en milisegundos entre antes y después de la llamada para medir el tiempo transcurrido. Supongo que primero ejecutó la aplicación de subproceso único. Si intenta ejecutar primero la aplicación de subprocesos múltiples, notará que tiene un valor “tiempo en milisegundos” más bajo.

Segundo. La creación y administración de subprocesos tiene una sobrecarga, que es mucho mayor que el tiempo de ejecución de las operaciones aritméticas muy simples que realiza. Si intenta iterar las operaciones unos pocos millones de veces, puede ver una ganancia de rendimiento al ejecutar las operaciones en paralelo.

Si considera una máquina procesadora. Todos los hilos se ejecutan en un solo procesador. supongamos que su progtwig (jvm) tiene un tiempo de ejecución de 0.2 segundos en el procesador por segundo. Si ejecuta en un solo hilo, los 0.2 segundos estarán dedicados solo a este hilo principal. Si lo ejecuta en 4 hilos, por ejemplo, los 0.2 segundos, no tendrá 0.05 + 0.05 + 0.05 + 0.05. Tendrá que agregar un tiempo extra para sincronizar, reanudar y eliminar los hilos. Si suponemos que esta operación lleva 0.001 segundos para cada cambio de contexto. Obtendrá 0.004 segundos de tiempo de ejecución perdido cada segundo siempre que un hilo se ejecute una vez en un segundo. En la vida real, el cambio de contexto de hilo se realiza muchas veces por segundo y es impredecible. Ahora las cosas están cambiando ya que hay máquinas multinúcleo y los hilos pueden ejecutarse al mismo tiempo en diferentes núcleos.

Consulte este enlace para obtener más información: ¿Tiene Java compatibilidad con procesadores multinúcleo / parallel processing?