Pregunta

cómo configurar un tiempo de espera para un método ocupado + C #.

¿Fue útil?

Solución

Ok, aquí está la verdadera respuesta.

...

void LongRunningMethod(object monitorSync)
{
   //do stuff    
   lock (monitorSync) {
     Monitor.Pulse(monitorSync);
   }
}

void ImpatientMethod() {
  Action<object> longMethod = LongRunningMethod;
  object monitorSync = new object();
  bool timedOut;
  lock (monitorSync) {
    longMethod.BeginInvoke(monitorSync, null, null);
    timedOut = !Monitor.Wait(monitorSync, TimeSpan.FromSeconds(30)); // waiting 30 secs
  }
  if (timedOut) {
    // it timed out.
  }
}

   ...

Esto combina dos de las partes más divertidas de usar C #. En primer lugar, para llamar al método de forma asíncrona, use un delegado que tenga la magia BeginInvoke de fancy-pants.

Luego, use un monitor para enviar un mensaje desde LongRunningMethod de vuelta al ImpatientMethod para avisarle cuando haya terminado, o si no ha tenido noticias de él. en un cierto período de tiempo, simplemente renunciar a él.

(p.s.- Solo bromeo acerca de que esta es la respuesta real. Sé que hay 2 ^ 9303 formas de pelear a un gato. Especialmente en .Net)

Otros consejos

No puedes hacer eso, a menos que cambies el método.

Hay dos formas:

  1. El método está construido de tal manera que él mismo mide el tiempo que se ha estado ejecutando, y luego regresa prematuramente si supera algún umbral.
  2. El método se construye de tal manera que supervisa una variable / evento que dice "cuando esta variable esté establecida, salga", y luego tiene otro hilo que mide el tiempo empleado en el primer método, y luego establece esa variable cuando el tiempo transcurrido ha superado algún umbral.

La respuesta más obvia, pero lamentablemente incorrecta, que puede obtener aquí es " Simplemente ejecute el método en un hilo y use Thread.Abort cuando se haya ejecutado durante demasiado tiempo " ;.

La única forma correcta es que el método coopere de manera que haga una salida limpia cuando se haya estado ejecutando durante demasiado tiempo.

También hay una tercera forma, donde ejecutas el método en un subproceso separado, pero después de esperar a que termine, y demora mucho en hacerlo, simplemente dices " No voy a esperar a que Termina, pero solo descártala " ;. En este caso, el método aún se ejecutará y, finalmente, terminará, pero el otro hilo que lo estaba esperando simplemente se rendirá.

Piense en la tercera forma que es llamar a alguien y pedirle que busque en su casa el libro que les prestó, y después de esperar 5 minutos en su teléfono, simplemente dice "aw, chuck it " ;, y colgar. Finalmente, esa otra persona encontrará el libro y volverá al teléfono, solo para darse cuenta de que ya no le importa el resultado.

Si bien La respuesta de MojoFilter es agradable puede provocar fugas si el " LongMethod " se congela Debe ABORTAR la operación si ya no está interesado en el resultado.

public void LongMethod()
{
    //do stuff
}

public void ImpatientMethod()
{
    Action longMethod = LongMethod; //use Func if you need a return value

    ManualResetEvent mre = new ManualResetEvent(false);

    Thread actionThread = new Thread(new ThreadStart(() =>
    {
        var iar = longMethod.BeginInvoke(null, null);
        longMethod.EndInvoke(iar); //always call endinvoke
        mre.Set();
    }));

    actionThread.Start();
    mre.WaitOne(30000); // waiting 30 secs (or less)
    if (actionThread.IsAlive) actionThread.Abort();
}

Esta es una pregunta antigua, pero ahora tiene una solución más simple que no estaba disponible: ¡Tareas!

Aquí hay un código de ejemplo:

var task = Task.Run(() => LongRunningMethod());//you can pass parameters to the method as well
if (task.Wait(TimeSpan.FromSeconds(30)))
    return task.Result; //the method returns elegantly
else
    throw new TimeoutException();//the method timed-out

Puedes ejecutar el método en un subproceso separado, monitorearlo y forzarlo a salir si funciona demasiado tiempo. Una buena manera, si puede llamarlo como tal, sería desarrollar un atributo para el método en Publicar Sharp para que el código de observación no ensucie tu aplicación.

He escrito lo siguiente como código de muestra (tenga en cuenta la parte del código de muestra, funciona, pero podría tener problemas con los subprocesos múltiples, o si el método en cuestión captura la excepción ThreadAbortException):

static void ActualMethodWrapper(Action method, Action callBackMethod)
{
    try
    {
        method.Invoke();
    } catch (ThreadAbortException)
    {
        Console.WriteLine("Method aborted early");
    } finally
    {
        callBackMethod.Invoke();
    }
}

static void CallTimedOutMethod(Action method, Action callBackMethod, int milliseconds)
{
    new Thread(new ThreadStart(() =>
    {
        Thread actionThread = new Thread(new ThreadStart(() =>
        {
            ActualMethodWrapper(method, callBackMethod);
        }));

        actionThread.Start();
        Thread.Sleep(milliseconds);
        if (actionThread.IsAlive) actionThread.Abort();
    })).Start();
}

Con la siguiente invocación:

CallTimedOutMethod(() =>
{
    Console.WriteLine("In method");
    Thread.Sleep(2000);
    Console.WriteLine("Method done");
}, () =>
{
    Console.WriteLine("In CallBackMethod");
}, 1000);

Necesito trabajar en la legibilidad de mi código.

Los métodos no tienen tiempos de espera en C #, a menos que esté en el depurador o el sistema operativo cree que su aplicación ha "colgado". Incluso entonces el procesamiento continúa y siempre que no elimine la solicitud, se devolverá una respuesta y la aplicación seguirá funcionando.

Las llamadas a bases de datos pueden tener tiempos de espera.

¿Podría crear un Método asíncrono para que pueda seguir haciendo otras cosas mientras que el " ocupado " método completado?

Regularmente escribo aplicaciones en las que tengo que sincronizar tareas de tiempo crítico entre plataformas. Si puedes evitar el thread.abort deberías. Consulte http: // blogs.msdn.com/b/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx y http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation para obtener pautas sobre cuándo thread.abort es apropiado. Aquí están los conceptos que implemento:

  • Ejecución selectiva: solo se ejecuta si existe una posibilidad razonable de éxito (según la capacidad de cumplir con el tiempo de espera o la probabilidad de éxito del resultado en relación con otros elementos en cola). Si divide el código en segmentos y conoce aproximadamente el tiempo esperado entre los segmentos de tareas, puede predecir si debe omitir cualquier procesamiento posterior. El tiempo total se puede medir envolviendo las tareas de un objeto bin con una función recursiva para el cálculo del tiempo o teniendo una clase de controlador que vigile a los trabajadores para saber los tiempos de espera esperados.
  • Orfandad selectiva: solo espere el retorno si existe una probabilidad razonable de éxito. Las tareas indexadas se ejecutan en una cola administrada. Las tareas que exceden su tiempo de espera o el riesgo de causar otros tiempos de espera se quedan huérfanas y se devuelve un registro nulo en su lugar. Las tareas en ejecución más largas se pueden envolver en llamadas asíncronas. Consulte el ejemplo del contenedor de llamadas asíncronas: http://www.vbusers.com/codecsharp /codeget.asp?ThreadID=67&PostID=1
  • Selección condicional: similar a la ejecución selectiva pero basada en un grupo en lugar de una tarea individual. Si muchas de sus tareas están interconectadas, de manera que una ejecución exitosa o fallida hace que el procesamiento adicional sea irrelevante, cree un indicador que se verifique antes de que comience la ejecución y nuevamente antes de que comiencen las tareas secundarias. Esto es especialmente útil cuando está usando parallel.for u otras tareas de concurrencia en cola similares.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top