Estoy buscando buenas ideas para implementar una forma genérica de ejecutar una sola línea (o delegado anónimo) de código con un tiempo de espera.
TemperamentalClass tc = new TemperamentalClass();
tc.DoSomething(); // normally runs in 30 sec. Want to error at 1 min
Estoy buscando una solución que se pueda implementar con elegancia en muchos lugares donde mi código interactúa con el código temperamental (que no puedo cambiar).
Además, me gustaría que el código ofensivo de "tiempo de espera agotado" deje de ejecutarse si es posible.
Respuestas:
La parte realmente difícil aquí fue matar la tarea de larga duración al pasar el hilo ejecutor de la Acción de regreso a un lugar donde podría abortarse. Logré esto con el uso de un delegado envuelto que pasa el hilo para matar a una variable local en el método que creó el lambda.
Presento este ejemplo, para su disfrute. El método que realmente le interesa es CallWithTimeout. Esto cancelará el hilo de larga ejecución abortándolo y tragándose la ThreadAbortException :
Uso:
El método estático que hace el trabajo:
fuente
Estamos usando código como este en gran medida en la producción :
La implementación es de código abierto, funciona eficientemente incluso en escenarios de computación paralela y está disponible como parte de las Bibliotecas Compartidas de Lokad
Este código todavía tiene errores, puedes probar con este pequeño programa de prueba:
Hay una condición de carrera. Es claramente posible que se genere una ThreadAbortException después de que
WaitFor<int>.Run()
se llame al método . No encontré una forma confiable de solucionar esto, sin embargo, con la misma prueba no puedo reprobar ningún problema con la respuesta aceptada de TheSoftwareJedi .fuente
Bueno, podría hacer cosas con los delegados (BeginInvoke, con una devolución de llamada configurando un indicador, y el código original esperando ese indicador o tiempo de espera), pero el problema es que es muy difícil cerrar el código en ejecución. Por ejemplo, matar (o pausar) un hilo es peligroso ... así que no creo que haya una manera fácil de hacerlo de manera robusta.
Publicaré esto, pero tenga en cuenta que no es lo ideal: no detiene la tarea de larga duración y no se limpia correctamente en caso de falla.
fuente
Algunos cambios menores a la gran respuesta de Pop Catalin:
Se han agregado sobrecargas para apoyar al trabajador de señalización para cancelar la ejecución:
fuente
Así es como lo haría:
fuente
Acabo de eliminar esto ahora, por lo que podría necesitar alguna mejora, pero haré lo que quieras. Es una aplicación de consola simple, pero demuestra los principios necesarios.
fuente
¿Qué pasa con el uso de Thread.Join (int timeout)?
fuente