threading thread multithreading performance threadpool

multithreading - threading - thread python 3



¿Cuántos hilos son demasiados? (12)

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 hacerlo configurable e inicialmente configurarlo en 100, luego lanzar su software a la naturaleza y monitorear lo que sucede.

Si el uso de tu hilo aumenta a 3, entonces 100 es demasiado. Si permanece en 100 durante la mayor parte del día, póngalo a 200 y vea qué sucede.

De hecho, podría tener su propio código para monitorear el uso y ajustar la configuración para la próxima vez que comience, pero eso probablemente sea excesivo.

Para aclaración y elaboración:

No estoy abogando por rodar su propio subsistema de agrupación de hilos, por supuesto use el que tiene. Pero, ya que estaba preguntando acerca de un buen punto de corte para los subprocesos, asumo que la implementación de su grupo de subprocesos tiene la capacidad de limitar el número máximo de subprocesos creados (lo que es 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):

  • un número mínimo de hilos activos.
  • un número máximo de hilos.
  • apagando hilos que no han sido utilizados por un tiempo.

El primero establece una línea de base para el rendimiento mínimo en términos del cliente de 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 subprocesos activos. El tercero lo regresa a la línea de base en tiempos tranquilos 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 realizar el trabajo (B).

(A) es generalmente el uso de memoria (pilas, etc.) ya que un subproceso que no realiza ningún trabajo no utilizará gran parte de la CPU. (B) generalmente será un retraso en el procesamiento de las solicitudes a medida que vayan llegando, ya que debe esperar que un subproceso esté disponible.

Es por eso que mides. Como indicas, la gran mayoría de tus hilos estarán esperando una respuesta de la base de datos para que no se ejecuten. Hay dos factores que afectan la cantidad de subprocesos que debe permitir.

El primero es el número de conexiones DB disponibles. Esto puede ser un límite difícil a menos que pueda aumentarlo en el DBMS. Asumiré que su DBMS puede tomar un número ilimitado de conexiones en este caso (aunque lo ideal es que también esté midiendo eso).

Luego, la cantidad de hilos que deberías tener depende de tu uso histórico. El mínimo que debería tener en ejecución es el número mínimo que haya tenido en ejecución + A%, con un mínimo absoluto de (por ejemplo, y configurarlo 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 la disponibilidad durante un tiempo significativo (de modo que afecte el rendimiento de los clientes), debe aumentar el máximo permitido hasta que vuelva a ser un B% más alto.

En respuesta a la pregunta "¿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 la optimización. Está bien obtener un presupuesto de antemano, pero nunca se sabe qué producción le marcará el camino (razón por la cual todas estas cosas deberían ser configurables en el tiempo de ejecución). Esto es para detectar una situación como la duplicación inesperada de las llamadas de clientes que llegan.

Estoy escribiendo un servidor, y ramifico cada acción en un hilo cuando la solicitud es entrante. Hago esto porque casi todas las solicitudes hacen una consulta de base de datos. Estoy utilizando una biblioteca de subprocesos para reducir la construcción / destrucción de subprocesos.

Sin embargo, mi pregunta es: ¿cuál es un buen punto de corte para hilos de E / S como estos? Sé que solo sería una estimación aproximada, pero ¿estamos hablando de cientos? miles?

EDITAR:

Gracias a todos por sus respuestas, parece que voy a tener que probarlo para averiguar mi límite máximo de hilos. Sin embargo, la pregunta es: ¿cómo sé que he alcanzado ese techo? ¿Qué debo medir exactamente?


Como bien dijo Pax, mida, no adivine . Eso fue lo que hice para DNSwitness y los resultados fueron sorprendentes: el número ideal de subprocesos fue mucho mayor de lo que pensaba, algo así como 15,000 subprocesos para obtener los resultados más rápidos.

Por supuesto, depende de muchas cosas, por eso debes medirte.

¿Completar medidas (solo en francés) en Combien de fils d''exécution? .


Creo que esto es un poco esquivo para su pregunta, pero ¿por qué no incluirlos en procesos? Mi comprensión de las redes (desde los días nebulosos de antaño, realmente no codifico redes en absoluto) fue que cada conexión entrante puede manejarse como un proceso separado, porque entonces si alguien hace algo desagradable en su proceso, no lo hace. Nuke todo el programa.


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, puede ser más fácil ver si hay alguna razón por la que el comportamiento predeterminado del grupo de subprocesos no sea el mejor.

Puede encontrar más información sobre cómo debería funcionar esto aquí: http://en.wikipedia.org/wiki/Thread_pool_pattern


Esta pregunta ha sido discutida a fondo y no tuve la oportunidad de leer todas las respuestas. Pero hay algunas cosas que se deben tener en cuenta al observar el límite superior en el número de subprocesos simultáneos que pueden coexistir pacíficamente en un sistema determinado.

  1. Tamaño de pila de subprocesos: en Linux, el tamaño de pila de subprocesos predeterminado es de 8 MB (puede usar ulimit -a para averiguarlo).
  2. Máxima memoria virtual que soporta una variante de SO dada. Linux Kernel 2.4 admite un espacio de direcciones de memoria de 2 GB. Con Kernel 2.6, yo un poco más grande (3GB)
  3. [1] muestra los cálculos para el número máximo de subprocesos por Max VM admitido dado. Para 2.4 resulta ser alrededor de 255 hilos. para 2.6 el número es un poco más grande.
  4. ¿Qué tipo de programador de kernel tienes? Comparando el programador de kernel Linux 2.4 con 2.6, el último le ofrece una programación O (1) sin depender de la cantidad de tareas existentes en un sistema, mientras que la primera es más una O (n). Así también las capacidades SMP de la programación del núcleo también desempeñan un buen papel en el número máximo de hilos sostenibles en un sistema.

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 imponer la Afinidad de la CPU a un proceso determinado, así como a un subproceso dado para vincularlos a CPU específicas para evitar los gastos generales de migración de subprocesos entre las CPU y evitar problemas de efectivo frío.

Tenga en cuenta que uno puede crear miles de subprocesos a su voluntad, pero cuando Linux se queda sin VM, simplemente comienza a matar procesos (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 determinada de recursos. Con recursos constantes en este caso, CPU Cycles and Memory, la curva de la utilidad se aplana con cada vez más tareas).

Estoy seguro de que el programador del kernel de Windows también hace algo de este tipo para lidiar con el uso excesivo 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/


He escrito una serie de aplicaciones con múltiples subprocesos. Generalmente, permito que un archivo de configuración especifique la cantidad de posibles subprocesos. Cuando hice ajustes para clientes específicos, establecí el número lo suficientemente alto como para que mi uso de todos los núcleos de la CPU fuera bastante alto, pero no tan alto 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 algún cuello de botella, ya sea CPU, rendimiento de base de datos, rendimiento de disco, etc., agregar más subprocesos 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) otras aplicaciones.


La respuesta "grande" generalmente es un hilo por recurso limitado (procesador (límite de CPU), armado (límite de E / S), etc.) pero eso solo funciona si puede encaminar el trabajo al hilo correcto para el recurso ser accedido

Cuando eso no sea posible, considere 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 caché), pero para las armas, si no puede asignar una cuerda al brazo, entras en la teoría de colas y cuál es el número óptimo para mantener las armas ocupado. En general, estoy pensando que si no puede enrutar las solicitudes según el brazo utilizado, entonces 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, es posible que el subproceso en un punto acceda al disco, y en otro punto espere en una red. Esto aumenta el número de "grietas" donde los subprocesos adicionales pueden entrar y hacer un trabajo útil, pero también aumenta la oportunidad de que los subprocesos adicionales contaminen los cachés de los demás, etc., y atasquen el sistema.

Por supuesto, debe sopesar todo esto contra el "peso" de un hilo. Desafortunadamente, la mayoría de los sistemas tienen hilos muy pesados ​​(y lo que ellos llaman "hilos ligeros" a menudo no son hilos en absoluto), 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 hacer una enorme diferencia en la cantidad de hilos que son óptimos. En particular, los problemas de caché y los conflictos de bloqueo pueden limitar en gran medida la cantidad de concurrencia práctica.


Si sus subprocesos realizan algún tipo de trabajo que requiere un uso intensivo de recursos (CPU / Disco), rara vez verá beneficios más allá de uno o dos, y muchos de ellos eliminarán el rendimiento muy rápidamente.

El "mejor caso" es que sus subprocesos posteriores se detendrán mientras que los primeros se completarán, o algunos tendrán bloques de baja sobrecarga en recursos con baja contención. El peor de los casos es que comienzas a golpear el 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 subprocesos de trabajo desde un grupo de subprocesos (y sí, evitar la creación / destrucción continua de subprocesos es un gran primer paso).

La cantidad de subprocesos activos en este grupo se puede modificar y escalar según los hallazgos de su perfil, el hardware en el que se está ejecutando y otras cosas que pueden estar ocurriendo en la máquina.


Tantos hilos como los núcleos de CPU es lo que he escuchado muy a menudo.


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 la cantidad de subprocesos que pueden proceder en un momento dado. Sin embargo, si, como en su caso, se espera que los subprocesos esperen con frecuencia a que una base de datos ejecute una consulta, es probable que desee ajustar sus subprocesos según la cantidad de consultas simultáneas que la base de datos pueda procesar.


Una cosa que debe tener en cuenta es que python (al menos la versión basada en C) utiliza lo que se conoce como un bloqueo global de intérprete que puede tener un gran impacto en el rendimiento de las máquinas de varios núcleos.

Si realmente necesitas el python de multiproceso al máximo, deberías considerar usar Jython o algo así.


ryeguy, actualmente estoy desarrollando una aplicación similar y mi número de hilos está establecido en 15. Desafortunadamente, si lo aumento en 20, se bloquea. Entonces, sí, creo que la mejor manera de manejar esto es medir si su configuración actual permite más o menos que un número X de subprocesos.