Quiero activar una tarea para que se ejecute en un hilo de fondo. No quiero esperar a que se completen las tareas.
En .net 3.5 hubiera hecho esto:
ThreadPool.QueueUserWorkItem(d => { DoSomething(); });
En .net 4, el TPL es la forma sugerida. El patrón común que he visto recomendado es:
Task.Factory.StartNew(() => { DoSomething(); });
Sin embargo, el StartNew()método devuelve un Taskobjeto que implementa IDisposable. Esto parece ser pasado por alto por las personas que recomiendan este patrón. La documentación de MSDN sobre el Task.Dispose()método dice:
"Siempre llame a Eliminar antes de liberar su última referencia a la Tarea".
No puede invocar la disposición en una tarea hasta que se complete, por lo que, en primer lugar, hacer que el subproceso principal espere y elimine la llamada anularía el punto de hacerlo en un subproceso en segundo plano. Tampoco parece haber ningún evento completado / terminado que pueda usarse para la limpieza.
La página de MSDN en la clase Tarea no comenta sobre esto, y el libro "Pro C # 2010 ..." recomienda el mismo patrón y no hace ningún comentario sobre la eliminación de tareas.
Sé que si lo dejo, el finalizador lo atrapará al final, pero ¿volverá esto y me morderá cuando estoy haciendo mucho fuego y olvido tareas como esta y el hilo del finalizador se abruma?
Entonces mis preguntas son:
- ¿Es aceptable no llamar
Dispose()a laTaskclase en este caso? Y si es así, ¿por qué hay riesgos / consecuencias? - ¿Hay alguna documentación que discuta esto?
- ¿O hay una forma adecuada de deshacerse del
Taskobjeto que me he perdido? - ¿O hay otra forma de disparar y olvidar tareas con el TPL?
fuente

Respuestas:
Hay una discusión sobre esto en los foros de MSDN .
Stephen Toub, miembro del equipo pfx de Microsoft tiene esto que decir:
Actualización (octubre de 2012)
Stephen Toub ha publicado un blog titulado ¿Necesito deshacerme de las tareas? que proporciona más detalles y explica las mejoras en .Net 4.5.
En resumen: no es necesario deshacerse de los
Taskobjetos el 99% del tiempo.Hay dos razones principales para disponer de un objeto: liberar recursos no administrados de manera oportuna y determinista, y evitar el costo de ejecutar el finalizador del objeto. Ninguno de estos se aplica a la
Taskmayoría de las veces:Taskasigna el controlador de espera interno (el único recurso no administrado en elTaskobjeto) es cuando utiliza explícitamente elIAsyncResult.AsyncWaitHandledeTask, yTaskobjeto en sí no tiene un finalizador; el controlador está envuelto en un objeto con un finalizador, por lo que, a menos que esté asignado, no hay finalizador para ejecutar.fuente
EndInvokeen WinForms cuando se usaBeginInvokepara ejecutar código en el hilo de la interfaz de usuario). (2) Stephen Toub es bastante conocido como un orador habitual sobre el uso efectivo de PFX (por ejemplo, en channel9.msdn.com ), por lo que si alguien puede dar una buena guía, entonces es él. Tenga en cuenta su segundo párrafo: hay veces que dejar las cosas al finalizador es mejor.Este es el mismo tipo de problema que con la clase Thread. Consume 5 manejadores del sistema operativo pero no implementa IDisposable. Buena decisión de los diseñadores originales, por supuesto, hay pocas formas razonables de llamar al método Dispose (). Tendría que llamar a Join () primero.
La clase Task agrega un identificador a esto, un evento de reinicio manual interno. Cuál es el recurso del sistema operativo más barato que existe. Por supuesto, su método Dispose () solo puede liberar ese identificador de evento, no los 5 identificadores que consume Thread. Sí, no te molestes .
Tenga cuidado de que debería estar interesado en la propiedad IsFaulted de la tarea. Es un tema bastante feo, puede leer más al respecto en este artículo de la Biblioteca de MSDN . Una vez que maneje esto adecuadamente, también debe tener un buen lugar en su código para deshacerse de las tareas.
fuente
Threaden la mayoría de los casos, usa ThreadPool.Me encantaría ver a alguien sopesar la técnica que se muestra en esta publicación: Invocación de delegado asincrónico de tipo seguro para disparar y olvidar en C #
Parece que un método de extensión simple manejará todos los casos triviales de interactuar con las tareas y podrá llamar a disposed en él.
fuente
Taskinstancia devuelta porContinueWith, pero ver la cita de Stephen Toub es la respuesta aceptada: no hay nada que eliminar si nada realiza una espera de bloqueo en una tarea.Task disper = null; disper = tsk.ContinueWith(cnt => { cnt.Dispose(); disper.Dispose(); });