example ejemplo c# .net multithreading design design-decisions

c# - ejemplo - threadpool python



¿Cuándo no debería usar ThreadPool en.Net? (9)

¿Cuándo no debería usar ThreadPool en .Net?

Parece que la mejor opción es usar un ThreadPool, en cuyo caso, ¿por qué no es la única opción?

¿Cuáles son sus experiencias al respecto?


No estoy hablando como alguien con solo conocimiento teórico aquí. Escribo y mantengo aplicaciones de alto volumen que hacen un uso intensivo de subprocesos múltiples, y generalmente no encuentro el grupo de subprocesos como la respuesta correcta.

Ah, argumento de autoridad, pero siempre esté atento a las personas que podrían estar en el equipo kernel de Windows.

Ninguno de los dos discutía con el hecho de que si tienes algunos requisitos específicos, el .NET ThreadPool podría no ser lo correcto. A lo que nos oponemos es a la trivialización de los costos para la máquina de crear un hilo.

El gasto importante de crear un hilo en la razón de ser para el ThreadPool en primer lugar. No quiero que mis máquinas estén llenas de código escrito por personas que han sido mal informadas sobre el gasto de crear un hilo, y no saben, por ejemplo, que hace que se llame un método en cada DLL que es adjuntas al proceso (algunas de las cuales serán creadas por terceros), y que bien pueden calentar una gran cantidad de código que no necesita estar en la memoria RAM y que casi con seguridad no necesita estar en L1.

La forma de la jerarquía de la memoria en una máquina moderna significa que "distraer" a una CPU es lo peor que puedes hacer, y todos los que se preocupan por su oficio deberían trabajar arduamente para evitarlo.


@ Eric, voy a tener que estar de acuerdo con Dean. Los hilos son caros. No puede suponer que su programa es el único en ejecución. Cuando todos son codiciosos con los recursos, el problema se multiplica.

Prefiero crear mis hilos manualmente y controlarlos yo mismo. Mantiene el código muy fácil de entender.

Eso está bien cuando es apropiado. Sin embargo, si necesita un montón de hilos de trabajo, todo lo que ha hecho es complicar el código. Ahora tiene que escribir código para administrarlos. Si acaba de utilizar un grupo de subprocesos, obtendría toda la administración de subprocesos de forma gratuita. Y el grupo de subprocesos proporcionado por el lenguaje es muy probable que sea más robusto, más eficiente y menos problemático que lo que sea que saque para usted.

Thread t = new Thread(new ThreadStart(DoSomething)); t.Start(); t.Join();

Espero que normalmente tenga algún código adicional entre Start() y Join() . De lo contrario, el hilo adicional es inútil, y estás desperdiciando recursos sin ningún motivo.

La gente tiene demasiado miedo de los recursos utilizados por los hilos. Nunca he visto crear e iniciar un hilo que lleve más de un milisegundo. No existe un límite estricto en la cantidad de hilos que puede crear. El uso de RAM es mínimo. Una vez que tiene unos pocos cientos de hilos, la CPU se convierte en un problema debido a los cambios de contexto, por lo que en ese punto es posible que desee ser elegante con su diseño.

Un milisegundo es mucho tiempo en hardware moderno. Eso es 3 millones de ciclos en una máquina 3GHz. Y nuevamente, no eres el único que está creando hilos. Sus hilos compiten por la CPU junto con los hilos de todos los demás programas. Si usa hilos que no son demasiados, y también lo hace otro programa, entonces, juntos, utilizaron demasiados hilos.

En serio, no hagas la vida más compleja de lo necesario. No use el grupo de subprocesos a menos que necesite algo muy específico que ofrezca.

En efecto. No hagas la vida más compleja. Si su programa necesita múltiples hilos de trabajo, no reinvente la rueda. Usa el grupo de hilos. Es por eso que está ahí. ¿Podrías lanzar tu propia clase de cuerda?


@Eric

@Derek, no estoy exactamente de acuerdo con el escenario que usas como ejemplo. Si no sabe exactamente qué se está ejecutando en su máquina y exactamente cuántos hilos, asas, tiempo de CPU, RAM, etc. totales, que su aplicación usará bajo una cierta cantidad de carga, usted está en problemas.

¿Eres el único cliente objetivo para los programas que escribes? Si no, no puedes estar seguro de la mayor parte de eso. Generalmente no tienes idea cuando escribes un programa si se ejecutará de manera efectiva solo, o si se ejecutará en un servidor web golpeado por un ataque DDOS. No puede saber cuánto tiempo de CPU tendrá.

Suponiendo que el comportamiento de su programa cambia en función de la entrada, es raro saber exactamente cuánta memoria o tiempo de CPU consumirá su programa. Claro, debe tener una idea bastante buena de cómo se comportará su programa, pero la mayoría de los programas nunca se analizan para determinar exactamente cuánta memoria, cuántos identificadores, etc. se usarán, porque un análisis completo es costoso. Si no está escribiendo software en tiempo real, la recompensa no vale la pena el esfuerzo.

En general, afirmar saber exactamente cómo se comportará su programa es exagerado, y afirmar saber todo sobre la máquina se acerca a lo ridículo.

Y para ser sincero, si no sabe exactamente qué método debe usar: subprocesos manuales, grupo de subprocesos, delegados y cómo implementarlo para hacer exactamente lo que su aplicación necesita, tiene problemas.

No estoy completamente en desacuerdo, pero realmente no veo cómo eso es relevante. Este sitio está aquí específicamente porque los programadores no siempre tienen todas las respuestas.

Si su aplicación es lo suficientemente compleja como para exigir la aceleración de la cantidad de hilos que utiliza, ¿no va a querer casi siempre más control del que le da el marco?

No. Si necesito un grupo de hilos, usaré el que se proporciona, a menos y hasta que encuentre que no es suficiente. No asumiré simplemente que el grupo de subprocesos proporcionado es insuficiente para mis necesidades sin confirmar que ese sea el caso.

No estoy hablando como alguien con solo conocimiento teórico aquí. Escribo y mantengo aplicaciones de alto volumen que hacen un uso intensivo de subprocesos múltiples, y generalmente no encuentro el grupo de subprocesos como la respuesta correcta.

La mayor parte de mi experiencia profesional ha sido con programas de multiprocesamiento y multiprocesamiento. A menudo también he necesitado rodar mi propia solución. Eso no significa que el grupo de subprocesos no sea útil o apropiado en muchos casos. El grupo de subprocesos está diseñado para manejar subprocesos de trabajo. En los casos en que son adecuados los subprocesos de trabajo múltiples, el grupo de subprocesos proporcionado debería ser generalmente el primer enfoque.


A la respuesta de la pelea, agregaría que es mejor no usar un hilo ThreadPool si necesita garantizar que su hilo comenzará a funcionar inmediatamente. La cantidad máxima de subprocesos agrupados por subprocesos en ejecución está limitada por dominio de aplicación, por lo que su trabajo puede tener que esperar si están todos ocupados. Se llama "elemento de trabajo de usuario en cola", después de todo.

Dos advertencias, por supuesto:

  1. Puede cambiar el número máximo de subprocesos agrupados por subprocesos en el código, en tiempo de ejecución, por lo que no hay nada que le impida comprobar el número actual frente al número máximo y aumentar el máximo si es necesario.
  2. Alternar un nuevo hilo viene con su propia penalización de tiempo: si vale la pena que lo tomes depende de tus circunstancias.

Cuando va a realizar una operación que llevará mucho tiempo, o quizás una secuencia de fondo continua. Supongo que siempre se puede aumentar la cantidad de subprocesos disponibles en el grupo, pero no tiene sentido incurrir en los costos de administración de un hilo que nunca se devolverá al grupo.


Los grupos de subprocesos tienen sentido siempre que tenga el concepto de subprocesos de trabajo. Cada vez que puede dividir fácilmente el procesamiento en trabajos más pequeños, cada uno de los cuales puede procesarse de manera independiente, los hilos de trabajo (y, por lo tanto, un grupo de subprocesos) tienen sentido.

Los grupos de subprocesos no tienen sentido cuando se necesita un subproceso que realice acciones completamente diferentes y no relacionadas, que no pueden considerarse "trabajos"; por ejemplo, un hilo para el manejo de eventos de GUI, otro para el procesamiento de back-end. Las agrupaciones de subprocesos tampoco tienen sentido cuando el procesamiento forma una interconexión.

Básicamente, si tiene subprocesos que comienzan, procesan un trabajo y lo abandonan, es probable que el grupo de subprocesos sea el camino a seguir. De lo contrario, el grupo de subprocesos realmente no ayudará.


Los subprocesos de Threadpool son apropiados para tareas que cumplen los dos criterios siguientes:

  1. La tarea no tendrá que pasar mucho tiempo esperando que ocurra algo
  2. Todo lo que está esperando que termine la tarea probablemente estará esperando a que terminen muchas tareas, por lo que su prioridad de programación no afectará demasiado.

El uso de un subproceso de subprocesos en lugar de crear uno nuevo ahorrará una cantidad significativa pero limitada de tiempo. Si ese tiempo es significativo en comparación con el tiempo que llevará realizar una tarea, es probable que sea apropiado realizar una tarea de subprocesamiento. Sin embargo, cuanto mayor sea el tiempo requerido para realizar una tarea, menor será el beneficio de utilizar el grupo de subprocesos y mayor será la probabilidad de que la tarea impida la eficacia del subproceso.


MSDN tiene una lista de algunos motivos aquí:

http://msdn.microsoft.com/en-us/library/0ka9477y.aspx

Hay varios escenarios en los que es apropiado crear y administrar sus propios subprocesos en lugar de utilizar subprocesos de grupo de subprocesos:

  • Usted requiere un hilo de primer plano.
  • Necesita un hilo para tener una prioridad particular.
  • Tiene tareas que hacen que el hilo se bloquee durante largos períodos de tiempo. El grupo de subprocesos tiene un número máximo de subprocesos, por lo que una gran cantidad de subprocesos de grupo de subprocesos bloqueados podría impedir el inicio de tareas.
  • Debe colocar hilos en un apartamento de subproceso único. Todos los hilos ThreadPool están en el apartamento multiproceso.
  • Necesita tener una identidad estable asociada con el hilo, o dedicar un hilo a una tarea.

La única razón por la que no usaría ThreadPool para multihilo barato es si necesito ...

  1. interactuar con el método en ejecución (por ejemplo, para matarlo)
  2. ejecutar código en un hilo STA (esto me pasó a mí)
  3. mantener el hilo vivo después de que mi aplicación haya muerto (los hilos de ThreadPool son hilos de fondo)
  4. en caso de que necesite cambiar la prioridad del hilo. No podemos cambiar la prioridad de los hilos en ThreadPool, que es por defecto Normal.

PD: El artículo de MSDN "The Managed Thread Pool" contiene una sección titulada, "When Not to Use Thread Pool Threads" , con una lista muy similar pero un poco más completa de posibles motivos para no usar el grupo de subprocesos.

Hay muchas razones por las cuales necesitaría saltear el ThreadPool , pero si no las conoce, entonces el ThreadPool debería ser lo suficientemente bueno para usted.

Alternativamente, mira el nuevo Marco de Extensiones Paralelas , que tiene algunas cosas ordenadas que pueden satisfacer tus necesidades sin tener que usar el ThreadPool .