System.Timers.Timer vs System.Threading.Timer


564

Ostatnio sprawdzałem niektóre z możliwych timerów System.Threading.TimeriSystem.Timers.Timer są to te, które wydają mi się potrzebne (ponieważ obsługują pule wątków).

Tworzę grę i planuję używać wszelkiego rodzaju wydarzeń, w różnych odstępach czasu itp.

Który byłby najlepszy?

Odpowiedzi:


362

Ten artykuł zawiera dość wyczerpujące wyjaśnienie:

Porównywanie klas timerów w bibliotece klas .NET Framework ” - dostępny również jako plik .chm

Wydaje się, że szczególna różnica System.Timers.Timerpolega na aplikacjach wielowątkowych i dlatego jest bezpieczna dla wątków dzięki swojej SynchronizationObjectwłaściwości, podczas gdy System.Threading.Timerironicznie nie jest bezpieczna dla wątków od razu po wyjęciu z pudełka.

Nie wierzę, że istnieje różnica między nimi, ponieważ dotyczy to, jak małe mogą być twoje interwały.


69
Myślę, że ten fragment jest pouczający: „W przeciwieństwie do System.Windows.Forms.Timer, klasa System.Timers.Timer domyślnie wywołuje procedurę obsługi zdarzeń timera w wątku roboczym uzyskanym z puli wątków środowiska uruchomieniowego języka wspólnego (CLR) . [...] Klasa System.Timers.Timer zapewnia łatwy sposób poradzenia sobie z tym dylematem - udostępnia publiczną właściwość SynchronizingObject. Ustawienie tej właściwości na wystąpienie formularza Windows (lub kontrolki w formularzu Windows) spowoduje upewnij się, że kod w module obsługi zdarzeń Elapsed działa w tym samym wątku, w którym utworzono instancję obiektu SynchronizingObject. ”
mico,

7
Według wątku sekcji Bezpieczeństwo w Threading.Timer„s artykule MSDN , jest całkowicie bezpieczny wątku ...
Pieter

62
System.Threading.Timerjest tak „ironicznie”, że nie jest wątkowo bezpieczny, System.Threading.Threada nici uzyskane przez pulę. Tylko dlatego, że klasy te nie trzymają ręki i locksame zarządzają użyciem słowa kluczowego, nie oznacza, że ​​te klasy nie są bezpieczne dla wątków. Równie dobrze można powiedzieć, że System.Threading.Threadnie jest wątkowo bezpieczny, ponieważ jest dokładnie tak samo.
Kirk Woll

8
Interwał System.Timer.Timer może być tylko Int32 System.Threading.Timer interwał może wynosić do Int64
Brent

11
To niefortunne, że ta wysoce myląca (w najlepszym razie) odpowiedź została zaakceptowana i tak wysoko oceniona. Jedyne istotne stwierdzenie w samej odpowiedzi jest po prostu błędne. Nie SynchronizingObjectpowoduje, że sam obiekt timera jest bezpieczny dla wątków. Po prostu upewnia się, że Twój kod do obsługi zdarzenia licznika czasu jest wywoływany w określonym wątku (jeśli odpowiednio ustawisz tę właściwość). Sam obiekt timera nie jest gwarantowany pod kątem bezpieczeństwa wątków, jak to wyraźnie zaznaczono w dokumentacji. Z drugiej strony System.Threading.Timerobiekt jest specjalnie udokumentowany jako bezpieczny dla wątków.
Peter Duniho,

169

System.Threading.Timerjest zwykłym zegarem. Wywołuje cię z powrotem w wątku puli wątków (z puli procesów roboczych).

System.Timers.Timerjest to, System.ComponentModel.Componentktóre otacza a System.Threading.Timer, i zapewnia pewne dodatkowe funkcje używane do wysyłania w określonym wątku.

System.Windows.Forms.Timerzamiast tego pakuje natywny HWND tylko do wiadomości i używa Timerów Windows do wywoływania zdarzeń w tej pętli komunikatów HWND.

Jeśli Twoja aplikacja nie ma interfejsu użytkownika, a chcesz jak najlżejszy i najbardziej uniwersalny zegar .Net (ponieważ z przyjemnością wymyślasz własne wątki / wysyłanie) System.Threading.Timer jest tak dobry, jak to możliwe w środowisku.

Nie jestem do końca jasne, z jakimi rzekomymi problemami System.Threading.Timersą „nie wątkowe” . Być może jest to to samo, co zadane w tym pytaniu: Bezpieczeństwo wątków System.Timers.Timer vs. System.Threading.Timer , a może wszyscy po prostu oznaczają, że:

  1. łatwo jest pisać warunki wyścigu, korzystając z liczników czasu. Np. Zobacz to pytanie: Bezpieczeństwo wątków Timer (System.Threading)

  2. ponowne wejście powiadomień timera, w którym zdarzenie timera może się uruchomić i oddzwonić po raz drugi, zanim zakończysz przetwarzanie pierwszego zdarzenia. Np. Patrz pytanie: Bezpieczne wykonywanie wątków za pomocą System.Threading.Timer i Monitor


Prawda System.Timers.Timerzastosowania System.Threading.Timerwewnętrznie. Zobacz kod źródłowy .
stomy

120

W swojej książce „ CLR Via C #Jeff Ritcher odradza korzystanie z System.Timers.Timertego timera System.ComponentModel.Component, co pozwala na jego wykorzystanie w powierzchni projektowej Visual Studio. Przydałoby się to tylko wtedy, gdy chcesz mieć zegar na powierzchni projektowej.

Preferuje System.Threading.Timerwykonywanie zadań w tle w wątku puli wątków.


36
Może być stosowany na powierzchni projektowej - nie oznacza to, że musi być, i nie ma negatywnych skutków z tego powodu. Czytając artykuł we wcześniejszej odpowiedzi na to pytanie, Timers.Timer wydaje się znacznie bardziej preferowany niż Threading.Timer.
Stephen Drew

6
Co jest lepsze, zależy od kontekstu, prawda? Jak rozumiem, System.Threading.Timer wykonuje przekazane wywołanie zwrotne dla nowego wątku roboczego z ThreadPool. Zakładam również, że nie zawsze jest to bezpieczne dla wątków. Trochę ma to sens. Teoretycznie nie musiałbyś się martwić o cholerstwo, które spowodowało rozwinięcie własnego wątku roboczego, ponieważ ten licznik zrobi to za Ciebie. Trochę to wydaje się absurdalnie przydatne.
Finster

6
Korzystanie System.Threading.Timerjest podobne do korzystania z puli wątków lub tworzenia własnego wątku. Z Oczywiście te zajęcia nie obsługuje synchronizacji dla ciebie - to twoja praca! Ani wątek puli wątków, twój własny wątek, ani wywołanie zwrotne licznika czasu nie poradzą sobie z blokowaniem - na jakim obiekcie, w jakiej modzie iw jakich okolicznościach musisz zablokować, wymaga dobrej oceny, a wersja licznika wątków zapewnia największą elastyczność i ziarnistość.
Kirk Woll

2
-1 ta odpowiedź jest subiektywna lub wyrażana od samego początku i nie zawiera konkretnych informacji na temat tego, dlaczego System.Threading.Timer jest preferowany przez Jeffa Ritchera
Brian Ogden

42

Informacje od Microsoft na ten temat (patrz Uwagi na MSDN ):

  • System.Timers.Timer , który uruchamia zdarzenie i wykonuje kod w co najmniej jednym zdarzeniu, w regularnych odstępach czasu. Klasa jest przeznaczona do użycia jako komponent serwerowy lub usługowy w środowisku wielowątkowym; nie ma interfejsu użytkownika i nie jest widoczny w czasie wykonywania.
  • System.Threading.Timer , który wykonuje pojedynczą metodę wywołania zwrotnego w wątku puli wątków w regularnych odstępach czasu. Metoda wywołania zwrotnego jest definiowana, gdy licznik czasu jest tworzony i nie można go zmienić. Podobnie jak klasa System.Timers.Timer, ta klasa jest przeznaczona do użycia jako komponent serwerowy lub usługowy w środowisku wielowątkowym; nie ma interfejsu użytkownika i nie jest widoczny w czasie wykonywania.
  • System.Windows.Forms.Timer (tylko .NET Framework), składnik Windows Forms, który uruchamia zdarzenie i wykonuje kod w jednym lub kilku obiektach przechwytujących w regularnych odstępach czasu. Komponent nie ma interfejsu użytkownika i jest przeznaczony do użytku w środowisku jednowątkowym; wykonuje się w wątku interfejsu użytkownika.
  • System.Web.UI.Timer (tylko .NET Framework), komponent ASP.NET, który wykonuje asynchroniczne lub synchroniczne zwrotne strony WWW w regularnych odstępach czasu.

Warto o tym wspomnieć System.Timers.Timer został wycofany z .NET Core 1.0, ale został ponownie zaimplementowany w .NET Core 2.0 (/ .NET Standard 2.0). Celem .NET Standard 2.0 było, aby przejście z systemu .NET Framework było jak najłatwiejsze, co prawdopodobnie jest przyczyną jego powrotu.

Kiedy było przestarzałe, zalecany był dodatek .NET Portability Analyzer Visual Studio Add-InSystem.Threading.Timer .

Wygląda na to, że Microsoft preferuje System.Threading.Timerwcześniej System.Timers.Timer.

INFORMACJA O EDYCJI 15.11.2018: Zmieniam rękę, ponieważ stare informacje o .NET Core 1.0 nie były już aktualne.



@Taegost, jego użycie jest również ograniczone - zobacz MSDN msdn.microsoft.com/en-us/library/... i przeczytaj uwagi na temat dostępności platformy.
astrowalker

@astrowalker - Dziękuję za to, że w momencie, gdy robiłem komentarz, ta odpowiedź nie miała prawie żadnych szczegółów. Ponieważ ma teraz szczegóły, o które pytałem, usunąłem swój komentarz.
Taegost

1
System.Timers.Timer jest teraz obsługiwany w .NET Standard 2.0 i .NET Core 2.0 i nowszych. docs.microsoft.com/en-us/dotnet/api/system.timers.timer (przewiń do końca artykułu)
Lee Grissom,


39

Jedną ważną, nie wymienioną powyżej różnicą, która może cię złapać, jest to, że System.Timers.Timercicho połyka wyjątki, podczas System.Threading.Timergdy nie.

Na przykład:

var timer = new System.Timers.Timer { AutoReset = false };
timer.Elapsed += (sender, args) =>
{
    var z = 0;
    var i = 1 / z;
};
timer.Start();

vs

var timer = new System.Threading.Timer(x =>
{
    var z = 0;
    var i = 1 / z;
}, null, 0, Timeout.Infinite);

1
Niedawno natrafiłem na ten problem z Timers.Timer i było to bardzo bolesne ... Jakieś pomysły, jak mogę przepisać z Threading.Timer? stackoverflow.com/questions/41618324/…
Tez Wingfield

7
W kodzie źródłowym jest pusty haczyk. Zobacz kod źródłowy System.Timers.Timer tutaj
stomy

Omgsh, dlaczego programiści MS nie są w stanie robić tych samych rzeczy naprawdę tak samo?
xmedeko

2
Przykład nie wyjaśnia, w jaki sposób jeden połyka wyjątki, a drugi nie. Czy ktoś mógłby wypełnić dane?
Sean

24

Znalazłem krótkie porównanie z MSDN

Biblioteka klas .NET Framework zawiera cztery klasy o nazwie Timer, z których każda oferuje inną funkcjonalność:

System.Timers.Timer, który uruchamia zdarzenie i wykonuje kod w jednym lub kilku obiektach przechwytujących w regularnych odstępach czasu. Klasa jest przeznaczona do użycia jako komponent serwerowy lub usługowy w środowisku wielowątkowym; nie ma interfejsu użytkownika i nie jest widoczny w czasie wykonywania.

System.Threading.Timer, która wykonuje pojedynczą metodę wywołania zwrotnego w wątku puli wątków w regularnych odstępach czasu. Metoda wywołania zwrotnego jest definiowana, gdy licznik czasu jest tworzony i nie można go zmienić. Podobnie jak klasa System.Timers.Timer, ta klasa jest przeznaczona do użycia jako komponent serwerowy lub usługowy w środowisku wielowątkowym; nie ma interfejsu użytkownika i nie jest widoczny w czasie wykonywania.

System.Windows.Forms.Timer, składnik Windows Forms, który uruchamia zdarzenie i wykonuje kod w jednym lub kilku obiektach przechwytujących w regularnych odstępach czasu. Komponent nie ma interfejsu użytkownika i jest przeznaczony do użytku w środowisku jednowątkowym.

System.Web.UI.Timer, komponent ASP.NET, który regularnie wykonuje asynchroniczne lub synchroniczne aktualizacje strony internetowej.


1

Te dwie klasy są funkcjonalnie równoważne, z wyjątkiem tego, że System.Timers.Timerma opcję wywoływania wszystkich wywołań zwrotnych upływu czasu przez ISynchronizeInvoke poprzez ustawienie SynchronizingObject . W przeciwnym razie oba liczniki wywołują wywołania zwrotne utraty ważności w wątkach puli wątków.

Podczas przeciągania znaku System.Timers.Timerna powierzchnię projektu Windows Forms Visual Studio ustawia SynchronizingObject na obiekt formularza, co powoduje, że wszystkie wywołania zwrotne wygasania są wywoływane w wątku interfejsu użytkownika.


1

Z MSDN: System.Threading.Timerto prosty, lekki licznik czasu, który wykorzystuje metody wywołania zwrotnego i jest obsługiwany przez wątki puli wątków. Nie zaleca się używania go z Windows Forms, ponieważ jego wywołania zwrotne nie występują w wątku interfejsu użytkownika. System.Windows.Forms.Timerjest lepszym wyborem do użycia z Windows Forms. W przypadku funkcji czasomierza opartej na serwerze można rozważyć użycie System.Timers.Timer, która wywołuje zdarzenia i ma dodatkowe funkcje.

Źródło

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.