Realmente me gusta esta pregunta:
¿La forma más sencilla de hacer un método de disparo y olvido en C #?
Solo quiero saber que ahora que tenemos extensiones Parallel en C # 4.0, ¿hay una forma mejor y más limpia de hacer Fire & Forget con Parallel linq?
c#
.net
.net-4.0
task-parallel-library
fire-and-forget
Jonathon Kresner
fuente
fuente
Respuestas:
No es una respuesta para 4.0, pero vale la pena señalar que en .Net 4.5 puede hacer esto aún más simple con:
El pragma es deshabilitar la advertencia que le dice que está ejecutando esta Tarea como disparar y olvidar.
Si el método dentro de las llaves devuelve una tarea:
Analicemos eso:
Task.Run devuelve una tarea, que genera una advertencia del compilador (advertencia CS4014) que indica que este código se ejecutará en segundo plano; eso es exactamente lo que deseaba, por lo que deshabilitamos la advertencia 4014.
De forma predeterminada, las tareas intentan "Marshal de nuevo en el subproceso original", lo que significa que esta tarea se ejecutará en segundo plano y luego intentará volver al subproceso que lo inició. A menudo, las Tareas de disparo y olvido finalizan una vez finalizado el hilo original. Eso hará que se lance una ThreadAbortException. En la mayoría de los casos, esto es inofensivo, solo te dice que intenté unirme, fallé, pero de todos modos no te importa. Pero todavía es un poco ruidoso tener ThreadAbortExceptions en sus registros en Producción o en su depurador en el desarrollo local.
.ConfigureAwait(false)
es solo una forma de mantenerse ordenado y decir explícitamente, ejecute esto en segundo plano, y eso es todo.Como esto es prolijo, especialmente el pragma feo, utilizo un método de biblioteca para esto:
Uso:
fuente
ConfigureAwait(false)
enTask.Run
cuando no lo haceawait
la tarea. El propósito de la función está en su nombre: "configure await ". Si no realizaawait
la tarea, no registra una continuación y no hay ningún código para que la tarea "vuelva al hilo original", como dice. El mayor riesgo es que se vuelva a lanzar una excepción no observada en el hilo del finalizador, que esta respuesta ni siquiera aborda.#Disable Warning BC42358
Con la
Task
clase sí, pero PLINQ es realmente para consultar colecciones.Algo como lo siguiente lo hará con Task.
O incluso...
O...
Donde
FireAway
estaEntonces, en virtud de la concisión del nombre de la clase y el método, esto supera a la versión de threadpool entre seis y diecinueve caracteres, según el que elija :)
fuente
fire and forget in ASP.NET WebForms and windows.close()
:?Tengo un par de problemas con la respuesta principal a esta pregunta.
En primer lugar, en una situación real de disparar y olvidar , probablemente no se hará
await
la tarea, por lo que es inútil agregarConfigureAwait(false)
. Si no lo hace,await
el valor devuelto porConfigureAwait
, no es posible que tenga ningún efecto.En segundo lugar, debe estar al tanto de lo que sucede cuando la tarea se completa con una excepción. Considere la solución simple que sugirió @ ade-miller:
Esto introduce un peligro: si una excepción no controlada se escapa de
SomeMethod()
, nunca se podrá observar que la excepción, y pueden 1 pueden volver a generar en el subproceso finalizador, bloquear su aplicación. Por lo tanto, recomendaría usar un método auxiliar para garantizar que se observen las excepciones resultantes.Podrías escribir algo como esto:
Esta implementación debe tener una sobrecarga mínima: la continuación solo se invoca si la tarea no se completa correctamente y debe invocarse de forma sincrónica (en lugar de programarse por separado de la tarea original). En el caso "perezoso", ni siquiera incurrirá en una asignación para el delegado de continuación.
Iniciar una operación asincrónica se vuelve trivial:
1. Este era el comportamiento predeterminado en .NET 4.0. En .NET 4.5, el comportamiento predeterminado se cambió de modo que las excepciones no observadas no se volvieran a lanzar en el hilo del finalizador (aunque aún puede observarlas a través del evento UnobservedTaskException en TaskScheduler). Sin embargo, la configuración predeterminada se puede anular, e incluso si su aplicación requiere .NET 4.5, no debe asumir que las excepciones de tareas no observadas serán inofensivas.
fuente
ContinueWith
se invoca debido a la cancelación, la propiedad de excepción del antecedente será Null y se lanzará una excepción de referencia nula. Establecer la opción de continuación de la tarea enOnlyOnFaulted
eliminará la necesidad de la verificación nula o comprobará si la excepción es nula antes de usarla.Task
convierte en un detalle de implementación.Task
" no es lo mismo que "Quiero una forma sencilla de iniciar una operación en segundo plano, nunca observar su resultado y no me importa qué mecanismo se utilice para hacerlo." Sobre esa base, respaldo mi respuesta a la pregunta que se hizo .fire and forget
en ASP.NET WebForms ywindows.close()
?Solo para solucionar algún problema que sucederá con la respuesta de Mike Strobel:
Si usa
var task = Task.Run(action)
y luego asigna una continuación a esa tarea, correrá el riesgo deTask
lanzar alguna excepción antes de asignar una continuación del controlador de excepciones alTask
. Por lo tanto, la clase siguiente debería estar libre de este riesgo:Aquí,
task
no se ejecuta directamente, sino que se crea, se asigna una continuación y solo entonces se ejecuta la tarea para eliminar el riesgo de que la tarea complete la ejecución (o arroje alguna excepción) antes de asignar una continuación.El
Run
método aquí devuelve la continuación,Task
por lo que puedo escribir pruebas unitarias asegurándome de que la ejecución esté completa. Sin embargo, puede ignorarlo con seguridad en su uso.fuente