2009-07-07 14 views
42

Używam usługi systemu Windows i za pomocą pętli i Thread.Sleep, aby powtórzyć zadanie, czy lepiej byłoby użyć metody licznika czasu?C# Timer lub Thread.Sleep

Jeśli tak przykład kodu byłoby świetnie

Obecnie używam tego kodu, aby powtórzyć

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

Odpowiedz

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

Kod mógł przypominać coś jak ten powyżej

+5

Należy pamiętać, że licznik czasu może podlegać dodatkowym straganom lub dużym obciążeniom, których sen może nie być. Powinno to zostać rozważone w czyimkolwiek wdrożeniu. –

11

Ważne jest, aby zrozumieć, że kod będzie spać przez 50 sekund między kończąc jedną pętlę, a wyjścia następny ...

Zegar wywoła pętlę co 50 sekund, co nie jest dokładnie takie samo.

Oba są poprawne, ale prawdopodobnie jest to zegar, którego szukasz.

4

Tak, użycie timera zwolni wątek, który obecnie spędza większość czasu na sen. Timer będzie również celniej strzelał co minutę, więc prawdopodobnie nie będziesz już potrzebował śledzenia lastMinute.

42

Zegar jest lepszym pomysłem, IMO. W ten sposób, jeśli twoja usługa zostanie poproszona o zatrzymanie, może zareagować na to bardzo szybko i po prostu nie zadzwonić ponownie do obsługi znacznika czasu ... Jeśli śpisz, menadżer usług będzie musiał poczekać 50 sekund lub zabić wątek, z których żaden nie jest strasznie miły.

+16

Aby uniknąć zabijania wątku, można użyć ManualResetEvent.WaitOne (50000) raczej niż Thread.Sleep(). Następnie możesz ustawić() uchwyt oczekiwania, aby zasygnalizować zakończenie wątku w najwcześniejszej dogodności. Jednak zegar prawdopodobnie nadal byłby preferowany w tym przypadku. – Thorarin

2

Niekoniecznie odpowiadając na pytanie, ale zamiast

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

powinny Prawdopodobnie masz

while(!error condition) 

też pójdę z Timer.

0

Możesz użyć jednego. Ale myślę, że Sleep() jest łatwy, jasny i krótszy do wdrożenia.

7

Pamiętaj, że nazywając uśpienia() będzie zatrzymać usługę, więc jeśli usługa jest wymagana do zatrzymania, to nie będzie reagować na okres, w jakim Funkcja Sleep().

1

Wymagałem, aby wątek był uruchamiany raz na minutę (see question here) i użyłem teraz DispatchTimer na podstawie odpowiedzi, które otrzymałem.

Odpowiedzi zawierają pewne odniesienia, które mogą okazać się przydatne.

+0

+1, aby wspomnieć o DispatchTimer – LamonteCristo

0

Zgadzam się również, użycie timera jest najlepszą opcją. Próbowałem rozwiązania podobnego do twojego w przeszłości i zacząłem mieć problemy, w których pętla nie wypaliłaby się, i musiałbym poczekać na inny Thread.Sleep(), zanim znowu wystrzeliłby. Ponadto, spowodowało to różnego rodzaju problemy z zatrzymaniem usługi, otrzymywałbym ciągłe błędy o tym, jak nie odpowiadał i musiał być zamknięty.

@ Kod Prashanth powinien być dokładnie tym, czego potrzebujesz.

1

Użyłem obu timerów i Thread.Sleep (x), albo też, w zależności od sytuacji.

Jeśli mam krótki fragment kodu, który musi zostać odtworzony, prawdopodobnie korzystam z licznika czasu.

Jeśli mam fragment kodu, który może potrwać dłużej niż licznik opóźnienia (np. Pobieranie plików ze zdalnego serwera przez FTP, gdzie nie kontroluję lub zna opóźnienie sieci lub rozmiary/liczebność pliku) , Poczekam na ustalony okres czasu między cyklami.

Oba są ważne, ale jak wskazano wcześniej, robią różne rzeczy. Timer uruchamia twój kod co x milisekund, nawet jeśli poprzednie wystąpienie nie zostało zakończone. Thread.Sleep (x) czeka na pewien okres czasu po zakończeniu każdej iteracji, więc całkowite opóźnienie na pętlę będzie zawsze dłuższe (być może nie dużo) niż okres snu.

+1

+1 za wskazanie, że podczas korzystania z Timera, kod _ może być uruchamiany wiele razy jednocześnie. – flocki

+0

Może, chyba że używasz semafora. – Casey

-1

Powiedziałabym, że sen to lepsza implementacja z automatem stanowym za nim. W ten sposób będziesz mieć kontrolę nad aplikacją przez cały czas, ale pozwalając na odpowiedź potrzebną w określonym czasie. To również będzie obsługiwać callbacków zegara, które są krótsze niż „czas realizacji obróbki w pętli”

Na przykład ..

<!-- 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

Jaką korzyść sprawi, że zasypianie przyda się za pomocą timera. Wielu innych dało wady snu, na które nie odpowiedzieliście. – Servy

+0

Moim kątem jest utrzymanie kontroli w aplikacji przez cały czas, sen i/lub długi czas nie pozwalają na przetwarzanie rzeczy w odstępach mniejszych niż wybrany okres oczekiwania. – Cr4t3r

+2

To jest problem z naiwną implementacją "Uśpienia", którą udoskonalasz. To nie jest żaden problem w rozwiązaniu opartym na 'Timer'; nie określa się przedziału czasu oczekiwania, definiuje się przedział czasu, w którym należy uruchomić zdarzenie, więc żadna z tych czynności, polegająca na określeniu, jak długo należy czekać, musi być wykonana w ogóle. – Servy