Domanda

come impostare un timeout per un metodo occupato + C #.

È stato utile?

Soluzione

Ok, ecco la vera risposta.

...

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.
  }
}

   ...

Questo combina due delle parti più divertenti dell'uso di C #. Prima di tutto, per chiamare il metodo in modo asincrono, usa un delegato che ha la magia BeginInvoke di fantasia-pantaloni.

Quindi, usa un monitor per inviare un messaggio da LongRunningMethod a ImpatientMethod per fargli sapere quando è finito, o se non ne ha sentito parlare in un certo lasso di tempo, arrenditi e basta.

(p.s.- Sto solo scherzando sul fatto che questa sia la vera risposta. So che ci sono 2 ^ 9303 modi per scuoiare un gatto. Soprattutto in .Net)

Altri suggerimenti

Non puoi farlo, a meno che non cambi il metodo.

Esistono due modi:

  1. Il metodo è costruito in modo tale da misurare da quanto tempo è in esecuzione, quindi restituisce prematuramente se supera una soglia.
  2. Il metodo è costruito in modo tale da monitorare una variabile / evento che dice "quando questa variabile è impostata, si prega di uscire da", quindi si ha un altro thread per misurare il tempo trascorso nel primo metodo, quindi impostare quella variabile quando il tempo trascorso ha superato una certa soglia.

La risposta più ovvia, ma sfortunatamente sbagliata, che puoi ottenere qui è " Basta eseguire il metodo in un thread e utilizzare Thread.Abort quando è stato eseguito per troppo tempo " ;.

L'unico modo corretto è che il metodo cooperi in modo tale da fare un'uscita pulita quando ha funzionato troppo a lungo.

C'è anche un terzo modo, in cui esegui il metodo su un thread separato, ma dopo aver aspettato che finisca, e ci vuole troppo tempo per farlo, dici semplicemente " Non aspetterò che termina, ma scartalo " ;. In questo caso, il metodo verrà comunque eseguito e alla fine terminerà, ma quell'altro thread che lo stava aspettando si arrenderà semplicemente.

Pensa al terzo modo di chiamare qualcuno e chiedere loro di cercare nella loro casa quel libro che gli hai prestato, e dopo aver atteso per 5 minuti la fine del telefono, dici semplicemente "aw, buttalo", e Appendere. Alla fine quell'altra persona troverà il libro e tornerà al telefono, solo per notare che non ti interessa più il risultato.

Mentre la risposta di MojoFilter è buona può portare a perdite se il "Metodo lungo" " congela. Dovresti interrompere l'operazione se non sei più interessato al risultato.

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();
}

Questa è una vecchia domanda ma ora ha una soluzione più semplice che non era disponibile allora: Compiti!

Ecco un codice di esempio:

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

Puoi eseguire il metodo in un thread separato, monitorarlo e forzarlo ad uscire se funziona troppo a lungo. Un buon modo, se puoi chiamarlo come tale, sarebbe sviluppare un attributo per il metodo in Post Sharp quindi il codice di sorveglianza non sta sporcando la tua applicazione.

Ho scritto quanto segue come codice di esempio (notare la parte di codice di esempio, funziona, ma potrebbe soffrire di problemi con il multithreading o se il metodo in questione cattura ThreadAbortException lo spezzerebbe):

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 seguente chiamata:

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

Devo lavorare sulla mia leggibilità del codice.

I metodi non hanno timeout in C #, a meno che tu non sia nel debugger o nel SO che la tua app sia "bloccata". Anche in questo caso l'elaborazione continua e finché non si annulla l'applicazione viene restituita una risposta e l'app continua a funzionare.

Le chiamate ai database possono avere timeout.

Potresti creare un Metodo asincrono in modo da poter continuare a fare altre cose mentre "occupato" metodo completato?

Scrivo regolarmente app in cui devo sincronizzare le attività temporali tra piattaforme. Se puoi evitare thread.abort dovresti. Vedi http: // blogs.msdn.com/b/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx e http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation per linee guida su quando thread.abort è appropriato. Ecco il concetto che implemento:

  • Esecuzione selettiva: viene eseguita solo se esiste una ragionevole possibilità di successo (in base alla capacità di soddisfare il timeout o la probabilità di un risultato di successo rispetto ad altri elementi in coda). Se si suddivide il codice in segmenti e si conosce approssimativamente il tempo previsto tra i blocchi di attività, è possibile prevedere se è necessario saltare ulteriori elaborazioni. Il tempo totale può essere misurato avvolgendo le attività di un contenitore oggetti con una funzione ricorsiva per il calcolo del tempo o disponendo di una classe controller che controlla i lavoratori per conoscere i tempi di attesa previsti.
  • Orfanotrofio selettivo: attendi il ritorno solo se esistono ragionevoli possibilità di successo. Le attività indicizzate vengono eseguite in una coda gestita. Le attività che superano il timeout o che rischiano di causare altri timeout vengono rimaste orfane e al loro posto viene restituito un record null. Le attività più lunghe possono essere racchiuse in chiamate asincrone. Vedi esempio wrapper di chiamata asincrono: http://www.vbusers.com/codecsharp /codeget.asp?ThreadID=67&PostID=1
  • Selezione condizionale: simile all'esecuzione selettiva ma basata sul gruppo anziché su singola attività. Se molte delle attività sono interconnesse in modo tale che un esito positivo o negativo renda irrilevante l'elaborazione aggiuntiva, creare un flag che viene verificato prima dell'inizio dell'esecuzione e di nuovo prima dell'inizio delle attività secondarie con esecuzione prolungata. Ciò è particolarmente utile quando si utilizzano parallel.for o altre attività di concorrenza simili in coda.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top