Tengo una pregunta estilística sobre la elección de la implementación de subprocesos de fondo que debo usar en una aplicación de formulario de Windows. Actualmente tengo BackgroundWorker
un formulario que tiene un (while(true))
bucle infinito . En este ciclo, uso WaitHandle.WaitAny
para mantener el hilo dormitando hasta que suceda algo interesante. Uno de los identificadores de eventos que espero es un " StopThread
" evento para poder salir del bucle. Este evento se señala desde mi anulación Form.Dispose()
.
Leí en algún lugar que BackgroundWorker
realmente está destinado a operaciones con las que no desea vincular la interfaz de usuario y tiene un fin finito, como descargar un archivo o procesar una secuencia de elementos. En este caso, el "final" es desconocido y solo cuando la ventana está cerrada. Por lo tanto, ¿sería más apropiado para mí usar un hilo de fondo en lugar de BackgroundWorker
para este propósito?
fuente
CancelAsync
(y pruebeCancellationPending
si su hilo se sondeará en intervalos cortos, si desea que se genere una excepción en su lugar, use unoSystem.Threading.Thread.Abort()
que genere una excepción dentro del bloque del hilo, elija el modelo correcto para la situación.Algunos de mis pensamientos ...
fuente
BackgroundWorker
está diseñado para informar el progreso del hilo a una parte interesada, lo que generalmente implica una interfaz de usuario. La documentación de MSDN para la clase lo deja muy claro. Si simplemente necesita realizar una tarea en segundo plano, prefiera usar unThreadPool
hilo.System.Windows.Forms
asamblea;BackgroundWorker
también es útil para aplicaciones WPF y esas aplicaciones pueden no tener una referencia a WinForms.Más o menos lo que dijo Matt Davis, con los siguientes puntos adicionales:
Para mí, el principal diferenciador
BackgroundWorker
es la clasificación automática del evento completado a través deSynchronizationContext
. En un contexto de UI, esto significa que el evento completado se dispara en el subproceso de UI y, por lo tanto, se puede usar para actualizar la IU. Este es un diferenciador importante si está utilizando elBackgroundWorker
en un contexto de interfaz de usuario.Las tareas ejecutadas a través de
ThreadPool
no se pueden cancelar fácilmente (esto incluyeThreadPool
.QueueUserWorkItem
Y los delegados se ejecutan de forma asíncrona). Por lo tanto, si bien evita la sobrecarga de la conexión de subprocesos, si necesita cancelación, use unaBackgroundWorker
o (más probablemente fuera de la interfaz de usuario) gire un hilo y mantenga una referencia para que pueda llamarAbort()
.fuente
También está atando un hilo de grupo de subprocesos durante la vida útil del trabajador en segundo plano, lo que puede ser preocupante ya que solo hay un número finito de ellos. Diría que si solo está creando el hilo una vez para su aplicación (y no está usando ninguna de las funciones del trabajador de fondo), use un hilo, en lugar de un hilo de trabajador de fondo / grupo de hilos.
fuente
Ya sabes, a veces es más fácil trabajar con un BackgroundWorker sin importar si estás usando Windows Forms, WPF o cualquier otra tecnología. La parte interesante de estos chicos es que tienes hilos sin tener que preocuparte demasiado sobre dónde se está ejecutando tu hilo, lo cual es ideal para tareas simples.
Antes de usar una
BackgroundWorker
consideración primero, si desea cancelar un hilo (cierre de la aplicación, cancelación del usuario), entonces debe decidir si su hilo debe verificar si hay cancelaciones o si se debe impulsar a la ejecución misma.BackgroundWorker.CancelAsync()
estableceráCancellationPending
atrue
pero no va a hacer nada más, es entonces la responsabilidad hilos para comprobar continuamente esto, tenga en cuenta también que usted podría terminar con una condición de carrera en este enfoque en el que el usuario ha cancelado, pero el hilo terminado antes de la prueba deCancellationPending
.Thread.Abort()
por otro lado, arrojará una excepción dentro de la ejecución del subproceso que obliga a la cancelación de ese subproceso, sin embargo, debe tener cuidado con lo que podría ser peligroso si esta excepción surgiera repentinamente dentro de la ejecución.El enhebrado necesita una consideración muy cuidadosa sin importar la tarea, para leer más:
Programación paralela en las mejores prácticas de subprocesos administrados de .NET Framework
fuente
Sabía cómo usar hilos antes de conocer .NET, así que me costó acostumbrarme cuando comencé a usar
BackgroundWorker
s. Matt Davis ha resumido la diferencia con gran excelencia, pero agregaría que es más difícil comprender exactamente lo que está haciendo el código, y esto puede dificultar la depuración. Es más fácil pensar en crear y cerrar hilos, IMO, que pensar en dar trabajo a un grupo de hilos.Todavía no puedo comentar las publicaciones de otras personas, así que perdona mi cojera momentánea al usar una respuesta para abordar los muelles7
En su
Thread.Abort();
lugar, no use , señale un evento y diseñe su hilo para que finalice con gracia cuando se lo indique.Thread.Abort()
plantea unThreadAbortException
en un punto arbitrario en la ejecución del hilo, que puede hacer todo tipo de cosas infelices como monitores huérfanos, estado compartido corrupto, etc.http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx
fuente
Si no está roto, arréglalo hasta que esté ... es broma :)
Pero en serio, BackgroundWorker es probablemente muy similar a lo que ya tienes, si hubieras comenzado desde el principio, tal vez hubieras ahorrado algo de tiempo, pero en este punto no veo la necesidad. A menos que algo no funcione, o piense que su código actual es difícil de entender, entonces me quedaría con lo que tiene.
fuente
La diferencia básica es, como usted dijo, generar eventos de GUI a partir de
BackgroundWorker
. Si el hilo no necesita actualizar la pantalla o generar eventos para el hilo principal de la GUI, entonces puede ser un hilo simple.fuente
Quiero señalar un comportamiento de la clase BackgroundWorker que aún no se mencionó. Puede hacer que un subproceso normal se ejecute en segundo plano configurando la propiedad Thread.IsBackground.
Puede probar este comportamiento llamando al siguiente método en el constructor de su ventana de formulario.
Cuando la propiedad IsBackground se establece en true y cierra la ventana, su aplicación finalizará normalmente.
Pero cuando la propiedad IsBackground se establece en false (de forma predeterminada) y cierra la ventana, solo desaparecerá la ventana pero el proceso seguirá ejecutándose.
La clase BackgroundWorker utiliza un subproceso que se ejecuta en segundo plano.
fuente
Un trabajador en segundo plano es una clase que funciona en un subproceso separado, pero proporciona una funcionalidad adicional que no se obtiene con un subproceso simple (como el manejo del informe de progreso de la tarea).
Si no necesita las funciones adicionales proporcionadas por un trabajador en segundo plano, y parece que no, un subproceso sería más apropiado.
fuente
Lo que me deja perplejo es que el diseñador visual del estudio solo le permite usar BackgroundWorkers y Timers que en realidad no funcionan con el proyecto de servicio.
Le brinda controles de arrastrar y soltar en su servicio, pero ... ni siquiera intente implementarlo. No funciona
Servicios: solo use System.Timers.Timer System.Windows.Forms.Timer no funcionará aunque esté disponible en la caja de herramientas
Servicios: BackgroundWorkers no funcionará cuando se esté ejecutando como un servicio. Utilice System.Threading.ThreadPools en su lugar o llamadas asíncronas.
fuente