2011-09-14 9 views
9

Ho un problema. Sto scrivendo un punto di riferimento e ho una funzione che viene eseguita in 2 secondi o dopo ~ 5 minuti (a seconda dei dati di input). E vorrei interrompere quella funzione se è eseguita per più di 3 secondi ...Come limitare il tempo di esecuzione di una funzione in c sharp?

Come posso farlo?

Grazie mille!

+0

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

+0

Sì, è un duplicato, il benchmark termina allo stesso modo degli altri fermi del thread. –

risposta

3

Il modo migliore sarebbe che la funzione può controllare il suo tempo di esecuzione spesso sufficiente per decidere di fermarlo ci vuole troppo tempo.

In caso contrario, eseguire la funzione in un thread separato. Nel thread principale avvia un timer di 3 secondi. Al termine del timer, elimina il thread separato utilizzando Thread.Abort() (ovviamente, a meno che la funzione non sia già terminata). Vedi codice di esempio e preacquisiti di utilizzo nei documenti di funzione.

+0

Davvero molto più facile. Se hai davvero bisogno di uccidere il thread in modo ostile, usare un thread è l'unico modo che conosco. – gjvdkamp

+0

sì, questo sembra essere il metodo più semplice e diretto. Grazie – Novellizator

0

Eseguire questa funzione nella discussione e terminarla dopo 3 secondi o controllare il tempo trascorso all'interno di questa funzione (penso che sia il ciclo lì).

+1

Ciò trasformerebbe semplicemente la funzione in un ciclo di verifica, senza lasciare altre funzionalità. Anche l'uccisione del thread non è garantita. Non verrà ucciso finché non uscirà comunque dalla funzione. –

0

Poiché il framework C# e .net non sono ambienti in tempo reale, non è possibile garantire nemmeno il conteggio dei 3 secondi. Anche se dovessi avvicinarti a questo, dovresti comunque chiamare lo

if(timeSpan > TimeSpan.FromSeconds(3) then goto endindentifier; prima di ogni altra chiamata nel metodo.

Tutto questo è solo sbagliato, quindi no, non c'è un modo affidabile per farlo da quello che so.

Anche se si può provare questa soluzione

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

ma proprio non farebbe queste cose in applicazione .net.

+0

Ciao, max. Microsoft Windows non è un sistema operativo in tempo reale –

+0

È possibile utilizzare i callback con i contatori hi perfomance su Windows utilizzando Win32 e interoperabilità, quindi –

+0

@Artur, il motivo per cui ho detto su .net e non windows, è perché C# può anche essere eseguito su Sistemi operativi basati su Unix tramite Mono, e non sono sicuro che tutti quei SO con supporto Mono non siano in tempo reale. Potrebbe essere possibile assemblare un sistema in tempo reale, ma Mono probabilmente non sarebbe mai in tempo reale, così come .Net, semplicemente perché non ce n'è bisogno, al momento. –

0

utilizza un sistema operativo callback con un contatore di prestazioni hi, poi uccidere il tuo thread, se esiste

+0

Il modo API di uccidere un thread gestito garantisce l'uccisione istantanea (in una successiva iterazione del processore)? –

3

È possibile utilizzare la forcella/unirsi al modello, nella Biblioteca Task Parallel questo è implementato 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"); 
} 

Questo inizierà l'altro compito su un thread separato, e quindi attendere per 3000 millisecondi per la sua finire. Se è terminato entro il timeout, restituisce true, altrimenti false, quindi è possibile utilizzarlo per decidere cosa fare dopo.

È possibile utilizzare uno CancellationToken per comunicare all'altro thread che risulta non è più necessario in modo che possa arrestarsi correttamente.

Cordiali saluti Gert-Gen

+0

ok, sembra facile e utilizzabile :) Un'ultima domanda: come posso annullare il loop in esecuzione() in qualche modo? – Novellizator

+0

Tipo di depende quello che stai facendo lì ... è un qualche tipo di loop (nel quale puoi ceckare il token di cancellazione?) O chiami in qualche altro codice che non puoi cambiare? Questo determina la strategia. Se l'operazione lunga runnnig è il tuo codice, allora fai il Ceppo su CancellationToken.Se si tratta di un altro codice, potrebbe essere necessario meno amichevole e davvero uccidere il thread. Questo potrebbe portare a uno stato incoerente però. Aggiornerò l'esempio con un token di cancellazione. – gjvdkamp

+0

ok esempio aggiornato – gjvdkamp

44

Bene ..., Ho avuto la stessa domanda, e dopo aver letto tutte le risposte qui e il blog di cui, ho optato per questo,

mi permette eseguo qualsiasi blocco di codice, con un limite di tempo, dichiarare il metodo involucro

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]; 
     } 
    } 

e l'uso che per avvolgere qualsiasi blocco di codice come questo

// code here 

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

    //More code 
+4

Da quanto ho capito, questo non fermerà l'azione codeBlock se è ancora in esecuzione dopo timeSpan. Nel tuo scenario di benchmarking dovresti modificare di molto i tuoi risultati se hai più codice in esecuzione in parallelo. –

+0

Penso che sia necessario scrivere 'Task task = new Task (codeBlock); task.Wait (TimeSpan); task.Start(); return task.IsCompleted; 'perché con il tuo codice, stai avviando il metodo e gli dici di aspettare x volte. Ma in realtà basta assegnare un compito di attesa e avviare l'attività è un approccio migliore. –

2

il miglior modo in C# per interrompere la funzione in mezzo è la parola chiave return in funzione, ma come faccio a sapere quando usare il return parola chiave per fermare la funzione in mezzo, dopo che dura almeno 3 secondi? La classe Stopwatch da System.Diagnostics è la risposta. Questa complicata funzione che dura da 2 secondi a 5 minuti (a seconda dei dati di input) utilizza logicamente molti cicli e forse anche ricorsione, quindi la mia soluzione per voi è che, al primo codice di linea di quella funzione, create un'istanza di Stopwatch utilizzando System.Diagnostics con la parola chiave new, avviarla richiamando la funzione Start() della classe cronometro, e, per ciascun ciclo e ciclo, all'inizio, aggiungere il seguente codice:

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

(suggerimento: è possibile digitare con le mani una volta, copiala Ctrl + C, e poi incollalo semplicemente Ctrl + V). Se tale funzione utilizza la ricorsione, per salvare la memoria, creare l'istanza globale Cronometro anziché crearla inizialmente come istanza locale e avviarla se non è in esecuzione all'inizio del codice. Lo puoi sapere con lo IsRunning della classe Cronometro. Dopodiché chiedi se il tempo trascorso è superiore a 3 secondi e se si (true) ferma o resetta il cronometro e usa la parola chiave return per interrompere il ciclo di ricorsione, ottimo avvio in funzione, se la tua funzione dura molto tempo a causa principalmente della ricorsione più che loop. È così. Come puoi vedere, è molto semplice, e ho provato questa soluzione, e i risultati hanno dimostrato che funziona! Prova tu stesso!

+0

La migliore risposta è semplice e veloce al punto. Hai un buon contenuto ma dovresti considerare di rivedere. – WolfLink

Problemi correlati