Pregunta

Me pregunto qué tan caro es tener muchos subprocesos en estado de espera en Java 1.6 x64.

Para ser más específico, estoy escribiendo una aplicación que se ejecuta en muchas computadoras y envía/recibe datos de una a otra.Me siento más cómodo teniendo un hilo separado para cada máquina y tarea conectada, como 1) enviar datos, 2) recibir datos, 3) restablecer la conexión cuando se interrumpe.Entonces, dado que hay N nodos en el clúster, cada máquina tendrá 3 subprocesos para cada uno de los N-1 vecinos.Normalmente habrá 12 máquinas, lo que equivale a 33 hilos de comunicación.

La mayoría de esos subprocesos estarán inactivos la mayor parte del tiempo, por lo que, con fines de optimización, podría reducir la cantidad de subprocesos y darle más trabajo a cada uno de ellos.Como por ejemplo.restablecer la conexión es responsabilidad del hilo receptor.O el envío a todas las máquinas conectadas se realiza mediante un solo hilo.

Entonces, ¿hay algún impacto significativo en el rendimiento por tener muchos hilos durmientes?

¿Fue útil?

Solución

En la mayoría de los casos, los recursos consumidos por un hilo inactivo serán su espacio de pila.Se sabe que el uso de un modelo de 2 subprocesos por conexión, que creo que es similar a lo que estás describiendo, causa grandes problemas de escalabilidad por esta misma razón cuando la cantidad de conexiones aumenta.

Yo mismo he estado en esta situación, y cuando el número de conexiones superó las 500 conexiones (alrededor de mil subprocesos), tiendes a encontrarte con muchos casos en los que obtienes OutOfMemoryError, ya que el uso del espacio de pila de subprocesos excede la cantidad máxima de memoria para un solo proceso.Al menos en nuestro caso, que estaba en un mundo Java en Windows de 32 bits.Supongo que puedes ajustar las cosas y llegar un poco más lejos, pero al final no es muy escalable ya que desperdicias mucha memoria.

Si necesita una gran cantidad de conexiones, Java NIO (nueva IO o lo que sea) es el camino a seguir, ya que permite manejar muchas conexiones en el mismo hilo.

Dicho esto, no debería encontrar muchos problemas con menos de 100 subprocesos en un servidor razonablemente moderno, incluso si probablemente sigue siendo un desperdicio de recursos.

Otros consejos

Tuvimos prácticamente el mismo problema antes de cambiarnos a NIO, por lo que apoyaré la recomendación de Liedman de utilizar ese marco.Deberías poder encontrar un tutorial, pero si quieres los detalles, te lo puedo recomendar. java-nio por Ron Hitchens.

El cambio a NIO aumentó mucho la cantidad de conexiones que podíamos manejar, lo cual fue realmente crítico para nosotros.

Esto no escalará muy bien.Tener una gran cantidad de subprocesos significa que la máquina virtual tiene que dedicar más tiempo al cambio de contexto y el uso de memoria será mayor debido a que cada subproceso requiere su propio espacio de pila.Sería mejor con un número menor de subprocesos procesándolos en forma de canalización, o utilizar el grupo de subprocesos con técnicas asincrónicas.

Muchos subprocesos equivalen a una gran cantidad de espacio en la pila, lo que consumirá su memoria; consulte la configuración de -Xss para saber cuánto y luego haga los cálculos.

Y si alguna vez tiene que hacer notifyAll() por algún motivo, entonces, por supuesto, estará activando muchos subprocesos adicionales, aunque es posible que no necesite hacerlo en la arquitectura propuesta.

No estoy seguro de que puedas evitar fácilmente tener un hilo por conector de escucha en este modelo (aunque sé muy poco sobre NIO, lo que podría solucionar incluso ese problema), pero échale un vistazo a java.util.concurrent.Ejecutor interfaz y sus clases de implementación para una manera decente de evitar tener demasiados hilos adicionales dando vueltas.De hecho, el ThreadPoolExecutor También podría ser una buena forma de administrar sus hilos de escucha, para no perder demasiado tiempo creando y destruyendo hilos innecesariamente.

A partir de las pruebas que he realizado en C, Lua y Python, puedes crear tu propia función de suspensión o espera con muy pocas líneas de código para crear un bucle simple y liviano.Utilice una variable local con la hora futura que desea alcanzar y luego pruebe la marca de tiempo actual en un bucle while.Si se encuentra en un ámbito en el que trabaja con fps, haga que la función de espera se ejecute una vez por cuadro para ahorrar recursos.Cuanta más precisión necesite, considere usar el reloj en lugar de la marca de tiempo, ya que la marca de tiempo está limitada a segundos.Cuantas más líneas de código agregue a una función de espera, menos precisa se volverá y más recursos consumirá, aunque cualquier contenido inferior a 10 líneas debería ser lo suficientemente rápido.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top