Estoy escribiendo un servidor y envío cada acción a un hilo separado cuando se recibe la solicitud. Hago esto porque casi todas las solicitudes realizan una consulta a la base de datos. Estoy usando una biblioteca de subprocesos para reducir la construcción / destrucción de subprocesos.
Mi pregunta es: ¿cuál es un buen punto de corte para hilos de E / S como estos? Sé que sería una estimación aproximada, pero ¿estamos hablando de cientos? Miles?
¿Cómo podría averiguar cuál sería este límite?
EDITAR:
Gracias a todos por sus respuestas, parece que voy a tener que probarlo para averiguar mi límite de conteo de hilos. Sin embargo, la pregunta es: ¿cómo sé que he alcanzado ese techo? ¿Qué debo medir exactamente?
Respuestas:
Algunas personas dirían que dos hilos son demasiados, no estoy del todo en ese campo :-)
Aquí está mi consejo: medir, no adivinar. Una sugerencia es hacer que sea configurable e inicialmente configurarlo en 100, luego lanzar su software a la naturaleza y monitorear lo que sucede.
Si el uso de su hilo alcanza un máximo de 3, entonces 100 es demasiado. Si permanece en 100 durante la mayor parte del día, aumente hasta 200 y vea qué sucede.
En realidad, podría hacer que su propio código monitoree el uso y ajuste la configuración para la próxima vez que se inicie, pero eso probablemente sea excesivo.
Para aclaraciones y elaboración:
No estoy abogando por la creación de su propio subsistema de agrupación de subprocesos, utilice el que tiene. Pero, como estaba preguntando acerca de un buen punto de corte para los subprocesos, supongo que la implementación de su grupo de subprocesos tiene la capacidad de limitar el número máximo de subprocesos creados (lo cual es algo bueno).
He escrito código de agrupación de conexiones de bases de datos y subprocesos y tienen las siguientes características (que creo que son esenciales para el rendimiento):
El primero establece una línea base para un rendimiento mínimo en términos del cliente del grupo de subprocesos (este número de subprocesos siempre está disponible para su uso). El segundo establece una restricción en el uso de recursos por hilos activos. El tercero lo regresa a la línea de base en tiempos de silencio para minimizar el uso de recursos.
Debe equilibrar el uso de recursos de tener subprocesos no utilizados (A) con el uso de recursos de no tener suficientes subprocesos para hacer el trabajo (B).
(A) es generalmente el uso de memoria (pilas, etc.) ya que un hilo que no funciona no utilizará gran parte de la CPU. (B) generalmente será un retraso en el procesamiento de las solicitudes a medida que lleguen, ya que debe esperar a que un hilo esté disponible.
Por eso lo mides. Como usted dice, la gran mayoría de sus hilos estarán esperando una respuesta de la base de datos para que no se ejecuten. Hay dos factores que afectan la cantidad de hilos que debe permitir.
El primero es el número de conexiones DB disponibles. Este puede ser un límite difícil a menos que pueda aumentarlo en el DBMS; voy a suponer que su DBMS puede tomar un número ilimitado de conexiones en este caso (aunque lo ideal es que también lo esté midiendo).
Luego, el número de hilos que debería tener depende de su uso histórico. El mínimo que debería tener en ejecución es el número mínimo que ha tenido en ejecución + A%, con un mínimo absoluto de (por ejemplo, y hacerlo configurable como A) 5.
El número máximo de hilos debe ser su máximo histórico + B%.
También debe estar monitoreando los cambios de comportamiento. Si, por alguna razón, su uso llega al 100% de lo disponible durante un tiempo significativo (de modo que afecte el rendimiento de los clientes), debe aumentar el máximo permitido hasta que nuevamente sea B% más alto.
En respuesta al "¿qué debo medir exactamente?" pregunta:
Lo que debe medir específicamente es la cantidad máxima de subprocesos en uso concurrente (por ejemplo, esperando un retorno de la llamada de DB) bajo carga. Luego agregue un factor de seguridad del 10%, por ejemplo (enfatizado, ya que otros carteles parecen tomar mis ejemplos como recomendaciones fijas).
Además, esto debe hacerse en el entorno de producción para el ajuste. Está bien obtener una estimación de antemano, pero nunca se sabe qué producción se le presentará (razón por la cual todas estas cosas deberían ser configurables en tiempo de ejecución). Esto es para detectar una situación como la duplicación inesperada de las llamadas entrantes del cliente.
fuente
Esta pregunta se ha discutido a fondo y no tuve la oportunidad de leer todas las respuestas. Pero aquí hay algunas cosas a tener en cuenta al mirar el límite superior en el número de hilos simultáneos que pueden coexistir pacíficamente en un sistema dado.
Ahora puede ajustar el tamaño de su pila para incorporar más subprocesos, pero luego debe tener en cuenta los gastos generales de la gestión de subprocesos (creación / destrucción y programación). Puede aplicar la afinidad de la CPU a un proceso determinado, así como a un subproceso determinado para vincularlos a CPU específicas para evitar gastos generales de migración de subprocesos entre las CPU y evitar problemas de liquidez.
Tenga en cuenta que uno puede crear miles de subprocesos a su gusto, pero cuando Linux se queda sin VM, comienza a matar procesos al azar (por lo tanto, subprocesos). Esto es para evitar que el perfil de la utilidad se maximice. (La función de utilidad informa sobre la utilidad de todo el sistema para una cantidad dada de recursos. Con recursos constantes en este caso CPU Cycles and Memory, la curva de utilidad se aplana con más y más cantidad de tareas).
Estoy seguro de que el programador de kernel de Windows también hace algo de este tipo para lidiar con la utilización excesiva de los recursos
[1] http://adywicaksono.wordpress.com/2007/07/10/i-can-not-create-more-than-255-threads-on-linux-what-is-the-solutions/
fuente
Si sus hilos están realizando algún tipo de trabajo intensivo en recursos (CPU / Disco), rara vez verá beneficios más allá de uno o dos, y demasiados matarán el rendimiento muy rápidamente.
El "mejor de los casos" es que sus subprocesos posteriores se detendrán mientras se completan los primeros, o algunos tendrán bloqueos de bajo costo en recursos con poca contención. El peor de los casos es que comienzas a destruir la memoria caché / disco / red y tu rendimiento general cae por el suelo.
Una buena solución es colocar solicitudes en un grupo que luego se envían a los subprocesos de trabajo desde un grupo de subprocesos (y sí, evitar la creación / destrucción continua de subprocesos es un gran primer paso).
El número de subprocesos activos en este grupo se puede ajustar y escalar en función de los resultados de su creación de perfiles, el hardware en el que se está ejecutando y otras cosas que pueden estar ocurriendo en la máquina.
fuente
Una cosa que debe tener en cuenta es que python (al menos la versión basada en C) usa lo que se llama un bloqueo de intérprete global que puede tener un gran impacto en el rendimiento en máquinas de múltiples núcleos.
Si realmente necesita sacar el máximo provecho de Python multiproceso, puede considerar usar Jython o algo así.
fuente
Como Pax dijo correctamente, mida, no adivine . Eso fue lo que hice para DNSwitness y los resultados fueron sorprendentes: el número ideal de hilos era mucho más alto de lo que pensaba, algo así como 15,000 hilos para obtener los resultados más rápidos.
Por supuesto, depende de muchas cosas, por eso debes medirte a ti mismo.
¿Medidas completas (solo en francés) en Combien de fils d'exécution? .
fuente
He escrito varias aplicaciones muy multiproceso. En general, permito que un archivo de configuración especifique el número de subprocesos potenciales. Cuando ajusté para clientes específicos, configuré el número lo suficientemente alto como para que mi utilización de todos los núcleos de CPU fuera bastante alta, pero no tanto como para tener problemas de memoria (estos eran sistemas operativos de 32 bits en el hora).
Dicho de otra manera, una vez que llegue a un cuello de botella, ya sea CPU, rendimiento de la base de datos, rendimiento del disco, etc., agregar más hilos no aumentará el rendimiento general. Pero hasta que llegues a ese punto, ¡agrega más hilos!
Tenga en cuenta que esto supone que los sistemas en cuestión están dedicados a su aplicación y que no tiene que jugar bien (evite morir de hambre) a otras aplicaciones.
fuente
La respuesta "gran hierro" es generalmente un subproceso por recurso limitado: procesador (enlazado a la CPU), armado (enlazado de E / S), etc., pero eso solo funciona si puede enrutar el trabajo al subproceso correcto para que el recurso ser accedido
Cuando eso no sea posible, tenga en cuenta que tiene recursos fungibles (CPU) y recursos no fungibles (brazos). Para las CPU no es crítico asignar cada subproceso a una CPU específica (aunque ayuda con la administración de la memoria caché), pero para los brazos, si no puede asignar un hilo al brazo, ingresa en la teoría de colas y cuál es el número óptimo para mantener los brazos ocupado. En general, estoy pensando que si no puede enrutar las solicitudes en función del brazo utilizado, tener 2-3 hilos por brazo será lo correcto.
Se produce una complicación cuando la unidad de trabajo pasada al hilo no ejecuta una unidad de trabajo razonablemente atómica. Por ejemplo, puede hacer que el hilo en un punto acceda al disco, en otro punto espere en una red. Esto aumenta el número de "grietas" en las que pueden entrar hilos adicionales y hacer un trabajo útil, pero también aumenta la oportunidad de que hilos adicionales contaminen las memorias caché de los demás, etc., y empantanen el sistema.
Por supuesto, debe sopesar todo esto contra el "peso" de un hilo. Desafortunadamente, la mayoría de los sistemas tienen subprocesos muy pesados (y lo que llaman "subprocesos livianos" a menudo no son subprocesos), por lo que es mejor errar en el lado bajo.
Lo que he visto en la práctica es que las diferencias muy sutiles pueden marcar una enorme diferencia en cuántos hilos son óptimos. En particular, los problemas de caché y los conflictos de bloqueo pueden limitar en gran medida la cantidad de concurrencia práctica.
fuente
Una cosa a considerar es cuántos núcleos existen en la máquina que ejecutará el código. Eso representa un límite estricto sobre cuántos subprocesos pueden continuar en un momento dado. Sin embargo, si, como en su caso, se espera que los subprocesos esperen con frecuencia que una base de datos ejecute una consulta, es probable que desee ajustar sus subprocesos en función de cuántas consultas simultáneas puede procesar la base de datos.
fuente
Creo que esto es un poco esquivo a su pregunta, pero ¿por qué no dividirlos en procesos? Mi comprensión de las redes (desde los días nebulosos de antaño, en realidad no codifico redes en absoluto) fue que cada conexión entrante se puede manejar como un proceso separado, porque si alguien hace algo desagradable en su proceso, no lo hace. Destruye todo el programa.
fuente
ryeguy, actualmente estoy desarrollando una aplicación similar y mi número de subprocesos está establecido en 15. Desafortunadamente, si lo aumento a 20, se bloquea. Entonces, sí, creo que la mejor manera de manejar esto es medir si su configuración actual permite o no más o menos que un número X de subprocesos.
fuente
En la mayoría de los casos, debe permitir que el grupo de subprocesos maneje esto. Si publica algún código o proporciona más detalles, podría ser más fácil ver si hay alguna razón por la cual el comportamiento predeterminado del grupo de subprocesos no sería el mejor.
Puede encontrar más información sobre cómo debería funcionar aquí: http://en.wikipedia.org/wiki/Thread_pool_pattern
fuente
Tantos hilos como núcleos de CPU es lo que he escuchado muy a menudo.
fuente