2009-07-07 20 views
42

Sto eseguendo un servizio di Windows e utilizzando un ciclo e Thread.Sleep per ripetere un'attività, sarebbe meglio utilizzare un metodo timer?C# Timer o Thread. Sonno

Se sì un esempio di codice sarebbe grande

Attualmente sto usando questo codice per ripetere

int curMinute; 
int lastMinute = DateTime.Now.AddMinutes(-1).Minute; 

while (condition) 
{ 
    curMinute = DateTime.Now.Minute; 

    if (lastMinute < curMinute) { 
     // do your once-per-minute code here 
     lastMinute = curMinute; 
    } 

    Thread.Sleep(50000);  // sleeps for 50 seconds 

    if (error condition that would break you out of this) { 
     break;  // leaves looping structure 
    } 
} 

risposta

30
class Program 
{ 
    static void Main(string[] args) 
    { 
     Timer timer = new Timer(new TimerCallback(TimeCallBack),null,1000,50000); 
     Console.Read(); 
     timer.Dispose(); 
    } 

    public static void TimeCallBack(object o) 
    { 
     curMinute = DateTime.Now.Minute; 
     if (lastMinute < curMinute) { 
     // do your once-per-minute code here 
     lastMinute = curMinute; 
    } 
} 

Il codice potrebbe somigliare a qualcosa come quello sopra

+5

Si noti che il timer potrebbe essere soggetto a stalli di sistema aggiuntivi o carichi elevati che il sonno potrebbe non. Questo dovrebbe essere considerato nell'implementazione di chiunque. –

11

E 'importante capire che il codice dormirà per 50 secondi tra termina un ciclo, e di partenza il prossimo ...

Un timer chiamerà il ciclo ogni 50 secondi, che non è esattamente lo stesso.

Sono entrambi validi, ma un timer è probabilmente quello che stai cercando qui.

4

Sì, l'utilizzo di un timer consente di liberare un thread che attualmente trascorre la maggior parte del tempo dormendo. Un timer farà anche fuoco più accuratamente ogni minuto, quindi probabilmente non dovrai più tenere traccia di lastMinute.

42

Un timer è un'idea migliore, IMO. In questo modo, se il tuo servizio viene richiesto di interromperlo, può rispondere a questo molto rapidamente e non chiamare nuovamente il gestore di tick del timer ... se stai dormendo, il gestore del servizio dovrà attendere 50 secondi o uccidere il tuo filo, nessuno dei quali è terribilmente bello.

+16

per evitare di uccidere il filo, è possibile utilizzare un ManualResetEvent.WaitOne (50000) piuttosto di un Thread.Sleep(). Quindi è possibile impostare() l'handle di attesa per segnalare il thread da terminare al più presto. In questo caso, un timer sarebbe probabilmente ancora preferibile in questo caso. – Thorarin

2

Non proprio rispondendo alla domanda, ma piuttosto che avere

if (error condition that would break you out of this) { 
     break;  // leaves looping structure 
    } 

Probabilmente si dovrebbe avere

while(!error condition) 

Inoltre, mi piacerebbe andare con un Timer.

0

È possibile utilizzare uno dei due. Ma penso che Sleep() sia facile, chiaro e più breve da implementare.

7

Attenzione che chiama sonno() si blocca il servizio, quindi se il servizio è invitato a fermarsi, non reagisce per tutta la durata del Chiamata Sleep().

1

Ho richiesto un thread per sparare una volta al minuto (see question here) e ora ho utilizzato uno DispatchTimer in base alle risposte che ho ricevuto.

Le risposte forniscono alcuni riferimenti che potrebbero essere utili.

+0

+1 per menzionare DispatchTimer – LamonteCristo

0

Concordo anch'io, l'utilizzo di un timer è l'opzione migliore. Ho provato una soluzione simile alla tua in passato e ho iniziato ad avere problemi in cui il loop si sarebbe infilato e dovevo aspettare un altro Thread.Sleep() prima che potesse sparare di nuovo. Inoltre, ha causato tutti i tipi di problemi con l'arresto del servizio, vorrei ottenere errori costanti su come non rispondeva e dovevo essere chiuso.

@ Il codice di Prashanth dovrebbe essere esattamente quello di cui hai bisogno.

1

Ho usato entrambi i timer e Thread.Sleep (x), o entrambi, a seconda della situazione.

Se ho un breve pezzo di codice che deve essere eseguito in modo irregolare, probabilmente utilizzo un timer.

Se si dispone di una parte di codice che potrebbe impiegare più tempo rispetto al timer di ritardo (ad esempio il recupero di file da un server remoto tramite FTP, dove non controllo o non conosco il ritardo della rete o le dimensioni/conteggio dei file) , Aspetterò un periodo di tempo fisso tra i cicli.

Entrambi sono validi, ma come indicato in precedenza fanno cose diverse. Il timer esegue il tuo codice ogni x millisecondi, anche se l'istanza precedente non è stata completata. Thread.Sleep (x) attende un periodo di tempo dopo aver completato ciascuna iterazione, quindi il ritardo totale per ciclo sarà sempre più lungo (forse non di molto) rispetto al periodo di sospensione.

+1

+1 per indicare che, quando si utilizza un timer, il codice _could_ deve essere eseguito più volte simultaneamente. – flocki

+0

Potrebbe, a meno che non si utilizzi un semaforo. – Casey

-1

Direi che dormire è un'implementazione migliore con una macchina di stato alle spalle. Ciò ti manterrà comunque in controllo dell'applicazione in qualsiasi momento, ma consentirà qualsiasi risposta necessaria in qualsiasi momento specifico. Ciò anche in grado di gestire i callback del timer che sono più corti rispetto al "tempo di esecuzione di elaborazione nel ciclo"

Per esempio ..

<!-- language: c# --> 
public enum State 
{ 
    Idle = 0, 
    Processing = 1, 
    Stop = 100, 
} 
public void Run() 
{ 
    State state = State.Idle; // could be a member variable, so a service could stop this too 

    double intervalInSeconds = 60; 
    System.DateTime nextExecution = System.DateTime.Now.AddSeconds(intervalInSeconds); 
    while (state != State.Stop) 
    { 
     switch (state) 
     { 
      case State.Idle: 
       { 
        if (nextExecution > System.DateTime.Now) 
        { 
         state = State.Processing; 
        } 
       } 
       break; 
      case State.Processing: 
       { 
        // do your once-per-minute code here 

        // if you want it to stop, just set it state to stop. 
        // if this was a service, you could stop execution by setting state to stop, also 
        // only time it would not stop is if it was waiting for the process to finish, which you can handle in other ways 

        state = State.Idle; 
        nextExecution = System.DateTime.Now.AddSeconds(intervalInSeconds); 
       } 
       break; 
      default: 
       break; 
     } 

     System.Threading.Thread.Sleep(1); 
    } 
} 
+1

E quale vantaggio senti addormentato durante l'uso di un timer. Un certo numero di altri ha dato degli svantaggi del sonno che non hai affrontato. – Servy

+0

il mio angolo è quello di mantenere il controllo nell'app in ogni momento, un sonno e/o un lungo timer non ti consentiranno di elaborare cose ad intervalli più piccoli del periodo di attesa selezionato. – Cr4t3r

+2

Questo è un problema con un'implementazione ingenua di 'Sleep', su cui si migliora. Non è nemmeno un problema in una soluzione basata su 'Timer'; non si definisce un intervallo di attesa, si definisce un intervallo di tempo in cui attivare l'evento, quindi nessuna di queste attività per determinare il tempo di attesa deve essere eseguita. – Servy