2011-09-14 22 views
9

Tengo un problema. Estoy escribiendo un punto de referencia y tengo una función que o bien se realiza en 2 segundos o después de ~ 5 minutos (dependiendo de los datos de entrada). Y me gustaría detener esa función si se ejecuta durante más de 3 segundos ...¿Cómo limitar el tiempo de ejecución de una función en c sharp?

¿Cómo puedo hacerlo?

¡Muchas gracias!

+0

posible duplicado http://stackoverflow.com/questions/5025509/how-to-estimate-method-execution-time – Reniuz

+0

Sí, es duplicado, la evaluación comparativa finaliza de la misma manera que cualquier otro hilo. –

Respuesta

3

La mejor manera sería que su función puede comprobar su tiempo de ejecución a menudo suficiente para decidir dejar que se tarda demasiado tiempo.

Si este no es el caso, ejecute la función en una secuencia separada. En su hilo principal, inicie un temporizador de 3 segundos. Cuando el temporizador haya transcurrido, elimine el hilo por separado utilizando Thread.Abort() (por supuesto, a menos que la función ya haya terminado). Consulte el código de muestra y las preacuaciones de uso en los documentos de función.

+0

Eso es mucho más fácil de hecho. Si realmente necesitas matar el hilo de una manera antipática, usar un hilo es la única forma que conozco. – gjvdkamp

+0

Sí, este parece ser el método más sencillo y directo. Gracias – Novellizator

0

Ejecute esta función en el hilo y elimínela después de 3 segundos o controle el tiempo transcurrido dentro de esta función (creo que es un bucle).

+1

Esto simplemente convertiría la función en un ciclo de verificación, sin dejar otra funcionalidad. Matar el hilo tampoco está garantizado. No se matará hasta que salga de la función de todos modos. –

0

Dado que C# y .NET Framework no son entornos en tiempo real, no puede garantizar ni siquiera el recuento de 3 segundos. Incluso si te acercas a eso, igual deberías llamar al

if(timeSpan > TimeSpan.FromSeconds(3) then goto endindentifier; antes de cada otra llamada en el método.

Todo esto simplemente está mal así que no, simplemente no hay una manera confiable de hacerlo por lo que sé.

Aunque puede probar esta solución

https://web.archive.org/web/20140222210133/http://kossovsky.net/index.php/2009/07/csharp-how-to-limit-method-execution-time

pero yo no haría tales cosas en la aplicación .NET.

+0

Hola, máx. Microsoft Windows tampoco es un sistema operativo en tiempo real. –

+0

Puede utilizar devoluciones de llamada con contadores de rendimiento en Windows utilizando Win32 e interoperabilidad, luego –

+0

@Artur, la razón que dije sobre .net y no en Windows, es porque C# también se puede ejecutar en Sistemas operativos basados ​​en Unix a través de Mono, y no estoy seguro si todos esos sistemas operativos Mono-compatibles no son en tiempo real. Puede ser posible ensamblar un sistema en tiempo real, pero el más probable es que Mono nunca sea en tiempo real, al igual que .Net, simplemente porque no lo necesita, actualmente. –

0

utilizar un devoluciones de llamada del sistema operativo con un contador de rendimiento de alta, y luego matar el hilo, si existe

+0

¿La forma API de matar un subproceso administrado garantiza la eliminación de subprocesos instantáneos (en una iteración de procesador siguiente)? –

3

Puede usar el tenedor/patrón unirse, en la Biblioteca Task Parallel esto se implementa con Task.WaitAll()

using System.Threading.Tasks; 

void CutoffAfterThreeSeconds() { 

    // start function on seperate thread 
    CancellationTokenSource cts = new CancellationTokenSource(); 
    Task loop = Task.Factory.StartNew(() => Loop(cts.Token)); 

    // wait for max 3 seconds 
    if(Task.WaitAll(new Task[]{loop}, 3000)){ 
     // Loop finished withion 3 seconds 
    } else { 
     // it did not finish within 3 seconds 
     cts.Cancel();   
    }   
} 

// this one takes forever 
void Loop() { 
    while (!ct.IsCancellationRequested) { 
     // your loop goes here 
    } 
    Console.WriteLine("Got Cancelled"); 
} 

Esto iniciará la otra tarea en un hilo separado, y luego esperar a 3000 milisegundos para que se terminar. Si terminó dentro del tiempo de espera, devuelve verdadero, de lo contrario es falso para que pueda usarlo para decidir qué hacer a continuación.

Puede usar un CancellationToken para comunicar al otro hilo que ya no se necesita, por lo que puede detenerse correctamente.

Saludos Gert-Jan

+0

bien, parece fácil y útil :) Una última pregunta: ¿cómo puedo cancelar el bucle en ejecución() de alguna manera? – Novellizator

+0

Tipo de depende de lo que está haciendo allí ... ¿se trata de algún tipo de bucle (en el que puede invocar el token de cancelación?) O ¿llama a algún otro código que no puede cambiar? Esto determina la estrategia. Si la operación de larga duración es su código, entonces confirma el CancelToken.Si se trata de algún otro código, es posible que necesites menos amigos y realmente matar el hilo. Esto podría conducir a un estado inconsistente sin embargo. Actualizaré el ejemplo con un token de cancelación. – gjvdkamp

+0

ok ejemplo actualizado – gjvdkamp

44

Bueno ..., Que tenía la misma pregunta, y después de leer todas las respuestas aquí y los blogs se refiere, me conformé con esto,

Me permite ejecuto cualquier bloque de código con un límite de tiempo, declarar el método de envoltura

public static bool ExecuteWithTimeLimit(TimeSpan timeSpan, Action codeBlock) 
    { 
     try 
     { 
      Task task = Task.Factory.StartNew(() => codeBlock()); 
      task.Wait(timeSpan); 
      return task.IsCompleted; 
     } 
     catch (AggregateException ae) 
     { 
      throw ae.InnerExceptions[0]; 
     } 
    } 

y usar eso para envolver cualquier bloque de código como este

// code here 

    bool Completed = ExecuteWithTimeLimit(TimeSpan.FromMilliseconds(1000),() => 
    { 
     // 
     // Write your time bounded code here 
     // 
    }); 

    //More code 
+4

Según tengo entendido, esto no detendrá la acción codeBlock si aún se está ejecutando después de timeSpan. En su escenario de evaluación comparativa que debería alterar en gran medida sus resultados si tiene código múltiple en ejecución en paralelo. –

+0

Creo que necesitas escribir 'Task task = new Task (codeBlock); task.Wait (timeSpan); task.Start(); return task.IsCompleted; 'porque con su código, está iniciando el método y le dice que espere x veces. Pero en realidad solo asignar una tarea de espera y comenzar la tarea es un mejor enfoque. –

2

la mejor manera en C# para detener la función en medio es la palabra clave return en función, pero ¿cómo sé cuándo usar el return palabra clave para detener la función en el medio, después de que dura al menos 3 segundos? La respuesta es la clase Stopwatch de System.Diagnostics. Esta función complicada que dura entre 2 segundos y 5 minutos (dependiendo de los datos de entrada) lógicamente utiliza muchos bucles, y tal vez incluso recursión, por lo que mi solución para usted es que, en el primer código de línea de esa función, cree una instancia de Stopwatch utilizando System.Diagnostics con la palabra clave new, iniciarlo llamando a la función Start() de la clase cronómetro, y en cada bucle y bucle, al principio, añada el siguiente código:

if (stopwatch.ElapsedMilliseconds >= 3000) { 
    stopwatch.Stop(); 
    // or 
    stopwatch.Reset(); 
    return; 
} 

(consejo: puede escribirla con las manos una vez, cópielo Ctrl + C, y luego simplemente péguelo Ctrl + V). Si esa función utiliza recursividad, para ahorrar memoria, cree la instancia global de cronómetro en lugar de crearla como instancia local al principio, e iníciela si no se ejecuta al principio del código. Puede saberlo con el IsRunning de la clase Cronómetro. Después de eso, pregunte si el tiempo transcurrido es más de 3 segundos, y si es así (true) detenga o reinicie el cronómetro y use la palabra clave return para detener el ciclo de recursión, muy buen inicio en la función, si su función dura mucho tiempo debido principalmente a recursión más que bucles. Que es. Como puede ver, es muy simple, y probé esta solución, ¡y los resultados mostraron que funciona! ¡Inténtalo tú mismo!

+0

La mejor respuesta es simple y rápida al grano. Tienes buen contenido, pero deberías considerar revisarlo. – WolfLink

Cuestiones relacionadas