c# - waitcallback - threadpool queueuserworkitem example
Ventaja de usar Thread.Start vs QueueUserWorkItem (9)
En la programación .NET multiproceso, ¿cuáles son los criterios de decisión para usar ThreadPool.QueueUserWorkItem frente a iniciar mi propio hilo a través de los nuevos Thread () y Thread.Start ()?
En una aplicación de servidor (digamos, una aplicación ASP.NET o un servicio WCF), creo que ThreadPool siempre está disponible y disponible. ¿Qué pasa con una aplicación cliente, como una aplicación WinForms o WPF? ¿Hay algún costo para aumentar el grupo de subprocesos? Si solo quiero que 3 o 4 hilos funcionen durante un período breve en algún cálculo, ¿es mejor QUWI o Thread.Start ()?
Aquí hay otra ventaja de usar ThreadPool.QueueUserWorkItem.
Tengo una aplicación de winforms que tiene buen oído. Originalmente implementé esto usando
heartbeat = new Thread(HeartbeatDoWork);
heartbeat.Start();
Lo cual funciona bien el 98% del tiempo. Sin embargo, cuando la aplicación se cierra, a veces no ''muere'' correctamente, es decir, el proceso aún es visible en el administrador de tareas.
Para ser breve, el latido del corazón publicó un evento y estaba manejando el evento (CAB pub / sub) donde se estaba "atascando".
La solución fue fácil, solo cambia a usar esto
ThreadPool.QueueUserWorkItem(HeartbeatDoWork);
Estoy seguro de que hay algunas cosas más que podría hacer al girar mi propio hilo y limpiarlo adecuadamente, pero esto es más simple, más rápido y más fácil de entender ... el ThreadPool hace todo el trabajo por mí.
El grupo de subprocesos siempre está disponible en aplicaciones .NET, independientemente de qué tipo.
El costo de iniciar un hilo desde el grupo de subprocesos a través de ThreadPool.QueueUserWorkItem
no será más que el costo de iniciar su propio hilo, y podría ser menor.
Si solo desea algunos hilos durante un período corto, utilice el grupo de hilos. Para eso es para eso.
Esta discusión te interesará
¿Cuándo no debería usar ThreadPool en .Net?
Iba a hacer un comentario, pero pasó demasiado tiempo.
CodemonkeyKing parece haber llegado a un punto importante, aunque no lo suficientemente fuerte en mi opinión.
Hay muchos criterios que puede usar para describir el código. ¿Será utilizado en una aplicación de larga ejecución o no? Aplicación Winforms o no? ¿Es una aplicación de servidor o cliente? biblioteca o exe independiente? etcétera etcétera.
Me parece que si tu código se ejecuta en una aplicación independiente y tienes control sobre todo el código circundante, puedes rodar tu propio grupo de subprocesos, iniciar tus propios subprocesos y medir y administrar el costo en el inicio del subproceso, latencia de subprocesos, y el consumo de recursos. O puede usar el QUWI, pero no matará su aplicación de ninguna manera. Eres libre de elegir.
Por otro lado, si su código está empaquetado como una biblioteca que puede usarse en un servidor -en ASP.NET, o tal vez en una aplicación SQL CLR, o un Servicio WCF- entonces es una mala idea crear subprocesos. Necesita usar QUWI o algún otro mecanismo que explote el grupo de subprocesos integrado (como BackgroundWorker). Si se va a usar en aplicaciones del lado del cliente con otras bibliotecas, una vez más, se requiere QUWI. Imagine que todas las bibliotecas que quieran aprovechar las computadoras multinúcleo hagan sus propios hilos. Habría un caos completo en las aplicaciones que usaban más de unas pocas bibliotecas. Hilos desenfrenados, todos compiten por los mismos recursos. Sin coordinación central de #threads vs # procesadores.
Un buen hygeine exige que una biblioteca, ya sea para ser consumida en aplicaciones de cliente o aplicaciones de servidor, use el grupo de subprocesos común, y eso significa QUWI.
Lo último que debe darse cuenta es esto;
Un hilo gestionado es un hilo de fondo o un hilo de primer plano. Los subprocesos de fondo son idénticos a los subprocesos de primer plano con una excepción: un subproceso en segundo plano no mantiene en ejecución el entorno de ejecución administrada. Una vez que todos los subprocesos de primer plano se han detenido en un proceso administrado (donde el archivo .exe es un ensamblado administrado), el sistema detiene todos los subprocesos de fondo y se apaga.
Los subprocesos que pertenecen al grupo de subprocesos administrados (es decir, los subprocesos cuya propiedad IsThreadPoolThread es verdadera) son subprocesos de fondo. Todos los hilos que ingresan al entorno de ejecución administrada desde un código no administrado se marcan como hilos de fondo. Todos los hilos generados al crear e iniciar un nuevo objeto Thread son por defecto hilos de primer plano.
Si usa un hilo para controlar una actividad, como una conexión de socket, establezca su propiedad IsBackground en true para que el hilo no impida que su proceso finalice.
desde el sitio de MSDN .
La mayoría de mis lecturas concuerdan con Marcel, la habilidad de controlar el hilo si algo va (Abortar ...) es algo que debería ser muy considerado, especialmente si estás tratando con llamadas de terceros sobre las cuales no tienes control y pueden colgar.
Si está creando sus propios hilos, tiene sentido comenzarlos en el primer uso y luego dejarlos por un tiempo en caso de que los necesite de nuevo: hace que un hilo inactivo espere un evento para que pueda reactivarlo señalizando el evento, y después de un tiempo suficientemente largo, el hilo se activará y saldrá, recuperando los recursos no utilizados. Al mantener una pequeña cantidad de subprocesos inactivos listos para ser reutilizados, se reduce la sobrecarga de la creación y destrucción constante de subprocesos (lo cual es significativo para operaciones suficientemente efímeras).
Pero esto es básicamente lo que la cola de hilos ya hace por ti, por lo que puedes usarlo también. Es un problema resuelto.
Un debate similar solía suceder en la comunidad de C ++ sobre cadenas, lo creas o no. ¿Deberíamos cada uno escribir nuestra propia clase de cuerda, o deberíamos usar std::string
? La respuesta depende de si desea aprender a escribir una clase de cuerda, o ha terminado con eso y desea seguir inventando algo nuevo.
Si sus tareas son cortas, lo más probable es que vea un rendimiento mucho mejor programando tareas en el grupo de subprocesos a través de QueueUserWorkItem o BeginInvoke, ya que evita el costo repetido de crear y destruir sus propios subprocesos.
El grupo de subprocesos también paga la creación de subprocesos, pero reutiliza los subprocesos, por lo que no paga el costo por tarea.
También es posible que desee echar un vistazo a Threading in C # (ebook gratuito).
Una ventaja del uso de Thread.Start()
es que puede abortar intencionalmente el hilo más tarde. En ThreadPool
no tienes forma de controlar la ejecución del hilo después de ponerlo en cola.
El ThreadPool siempre está ahí, sin embargo, hay un número finito de subprocesos asignados al grupo en función del número de procesadores. Para las aplicaciones ASP.NET, generalmente es una mala idea usar Threads a menos que realmente esté comenzando un proceso Async y sepa que no habrá un gran número de solicitudes (recuerde que hay un número finito de hilos en ThreadPool que compartes con todo lo que se ejecuta en tu AppDomain y hay un límite realista en el número total de subprocesos que deseas crear usando el nuevo Thread () también).
Para las aplicaciones de WinForms, considere usar BackgroundWorker en lugar de usar ThreadPool o ThreadPool. Utiliza el ThreadPool, sin embargo, hace que la comunicación entre hilos sea más fácil en el programador inteligente de múltiples hilos.
Actualizado
Evite utilizar ThreadPool.QueueUserWorkItem ya que su grupo de aplicaciones podría desaparecer en cualquier momento. Mueva este trabajo afuera o use WebBackgrounder si es necesario.
De Hanselman.com - "Lista de comprobación: qué NO hacer en ASP.NET"