Los tutoriales de Java dicen que crear un hilo es costoso. Pero, ¿por qué es exactamente caro? ¿Qué sucede exactamente cuando se crea un Java Thread que hace que su creación sea costosa? Estoy tomando la declaración como cierta, pero solo estoy interesado en la mecánica de la creación de subprocesos en JVM.
Subproceso de ciclo de vida superior. La creación de hilos y el desmontaje no son gratuitos. La sobrecarga real varía según las plataformas, pero la creación de subprocesos lleva tiempo, ya que introduce latencia en el procesamiento de solicitudes y requiere cierta actividad de procesamiento por parte de la JVM y el sistema operativo. Si las solicitudes son frecuentes y ligeras, como en la mayoría de las aplicaciones de servidor, la creación de un nuevo subproceso para cada solicitud puede consumir importantes recursos informáticos.
De la concurrencia de Java en la práctica
Por Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, Doug Lea
Imprimir ISBN-10: 0-321-34960-1
fuente
Respuestas:
La creación de hilos Java es costosa porque hay un poco de trabajo involucrado:
También es costoso en el sentido de que el hilo ata los recursos mientras esté vivo; por ejemplo, la pila de hilos, cualquier objeto accesible desde la pila, los descriptores de hilos JVM, los descriptores de hilos nativos del sistema operativo.
Los costos de todas estas cosas son específicos de la plataforma, pero no son baratos en ninguna plataforma Java que haya encontrado.
Una búsqueda en Google me encontró un viejo punto de referencia que informa una tasa de creación de subprocesos de ~ 4000 por segundo en un Sun Java 1.4.1 en un procesador dual 2002 Xeon con 2002 Linux vintage. Una plataforma más moderna dará mejores números ... y no puedo comentar sobre la metodología ... pero al menos da una pista sobre cuán costosa es la creación de hilos.
La evaluación comparativa de Peter Lawrey indica que la creación de subprocesos es significativamente más rápida en estos días en términos absolutos, pero no está claro cuánto de esto se debe a mejoras en Java y / o el sistema operativo ... o mayores velocidades de procesador. Pero sus números aún indican una mejora de más de 150 veces si usa un grupo de hilos en lugar de crear / comenzar un nuevo hilo cada vez. (Y él señala que todo esto es relativo ...)
(Lo anterior supone "hilos nativos" en lugar de "hilos verdes", pero las JVM modernas usan hilos nativos por razones de rendimiento. Los hilos verdes son posiblemente más baratos de crear, pero se paga en otras áreas).
He cavado un poco para ver cómo se asigna realmente la pila de un hilo de Java. En el caso de OpenJDK 6 en Linux, la pila de subprocesos se asigna por la llamada
pthread_create
que crea el subproceso nativo. (La JVM no pasapthread_create
una pila preasignada).Luego, dentro de
pthread_create
la pila se asigna mediante una llamada ammap
lo siguiente:Según
man mmap
, laMAP_ANONYMOUS
bandera hace que la memoria se inicialice a cero.Por lo tanto, aunque no sea esencial que las nuevas pilas de subprocesos de Java estén puestas a cero (según la especificación JVM), en la práctica (al menos con OpenJDK 6 en Linux) están puestas a cero.
fuente
malloc()
función C estándar , que la JVM bien podría usar, no garantiza que la memoria asignada esté en cero (presumiblemente para evitar tales problemas de rendimiento).mmap()
llamada estén asignadas de copia a escritura a una página cero, por lo que su inicialización ocurre no dentro demmap()
sí misma, sino cuando las páginas se escriben por primera vez , y luego solo una página en un momento. Es decir, cuando el hilo comienza a ejecutarse, con el costo generado por el hilo creado en lugar del hilo creador.Otros han discutido de dónde provienen los costos de enhebrar. Esta respuesta cubre por qué crear un hilo no es tan costoso en comparación con muchas operaciones, sino relativamente caro en comparación con las alternativas de ejecución de tareas, que son relativamente menos costosas.
La alternativa más obvia para ejecutar una tarea en otro subproceso es ejecutar la tarea en el mismo subproceso. Esto es difícil de entender para aquellos que suponen que más hilos son siempre mejores. La lógica es que si la sobrecarga de agregar la tarea a otro subproceso es mayor que el tiempo que ahorra, puede ser más rápido realizar la tarea en el subproceso actual.
Otra alternativa es usar un grupo de subprocesos. Un grupo de subprocesos puede ser más eficiente por dos razones. 1) reutiliza hilos ya creados. 2) puede ajustar / controlar el número de subprocesos para asegurarse de tener un rendimiento óptimo.
El siguiente programa imprime ...
Esta es una prueba para una tarea trivial que expone la sobrecarga de cada opción de subprocesamiento. (Esta tarea de prueba es el tipo de tarea que en realidad se realiza mejor en el hilo actual).
Como puede ver, crear un nuevo hilo solo cuesta ~ 70 µs. Esto podría considerarse trivial en muchos, si no en la mayoría, de los casos de uso. Relativamente hablando, es más costoso que las alternativas y, en algunas situaciones, un grupo de hilos o no usar hilos es una mejor solución.
fuente
En teoría, esto depende de la JVM. En la práctica, cada hilo tiene una cantidad relativamente grande de memoria de pila (256 KB por defecto, creo). Además, los subprocesos se implementan como subprocesos del sistema operativo, por lo que su creación implica una llamada del sistema operativo, es decir, un cambio de contexto.
Tenga en cuenta que "caro" en informática es siempre muy relativo. La creación de subprocesos es muy costosa en relación con la creación de la mayoría de los objetos, pero no es muy costosa en relación con una búsqueda aleatoria de disco duro. No tiene que evitar crear hilos a toda costa, pero crear cientos de ellos por segundo no es un movimiento inteligente. En la mayoría de los casos, si su diseño requiere muchos subprocesos, debe usar un grupo de subprocesos de tamaño limitado.
fuente
K
= 1024 yk
= 1000.;) en.wikipedia.org/wiki/KibibyteHay dos tipos de hilos:
Subprocesos adecuados : estas son abstracciones en torno a las instalaciones de subprocesos del sistema operativo subyacente. La creación de subprocesos es, por lo tanto, tan costosa como la del sistema: siempre hay una sobrecarga.
Hilos "verdes" : creados y programados por la JVM, son más baratos, pero no se produce un paralelismo adecuado. Estos se comportan como hilos, pero se ejecutan dentro del hilo JVM en el sistema operativo. No son de uso frecuente, que yo sepa.
El factor más importante que puedo pensar en la sobrecarga de creación de subprocesos es el tamaño de pila que ha definido para sus subprocesos. El tamaño de la pila de subprocesos se puede pasar como parámetro cuando se ejecuta la VM.
Aparte de eso, la creación de subprocesos depende principalmente del sistema operativo e incluso de la implementación de VM.
Ahora, permítame señalar algo: crear hilos es costoso si planea disparar 2000 hilos por segundo, cada segundo de su tiempo de ejecución. La JVM no está diseñada para manejar eso . Si tendrá un par de trabajadores estables que no serán despedidos y asesinados una y otra vez, relájese.
fuente
La creación
Threads
requiere la asignación de una buena cantidad de memoria, ya que tiene que hacer no una, sino dos nuevas pilas (una para el código Java, una para el código nativo). El uso de Executors / Thread Pools puede evitar la sobrecarga, reutilizando hilos para múltiples tareas para Executor .fuente
Obviamente, el quid de la cuestión es qué significa "caro".
Un hilo necesita crear una pila e inicializar la pila en función del método de ejecución.
Necesita configurar estructuras de estado de control, es decir, en qué estado se puede ejecutar, esperar, etc.
Probablemente haya una buena cantidad de sincronización en torno a la configuración de estas cosas.
fuente