System.Timers.Timer против System.Threading.Timer

565

Я проверить некоторые из возможных таймеров в последнее время, а System.Threading.Timerи System.Timers.Timerте , которые выглядят потребного для меня (так как они поддерживают пул потоков).

Я делаю игру, и я планирую использовать все типы событий, с разными интервалами и т. Д.

Что будет лучшим?

TheAJ
источник

Ответы:

363

Эта статья предлагает довольно полное объяснение:

« Сравнение классов таймеров в библиотеке классов .NET Framework » - также доступно в виде файла .chm

Конкретное различие заключается в том, что System.Timers.Timerоно ориентировано на многопоточные приложения и поэтому является поточно-ориентированным благодаря своему SynchronizationObjectсвойству, тогда как System.Threading.Timerпо иронии судьбы не является поточно- ориентированным из коробки.

Я не верю, что между этими двумя понятиями есть разница, поскольку они касаются того, насколько малы могут быть ваши интервалы.

Дэвид Андрес
источник
69
Я думаю, что этот отрывок поучителен: «В отличие от System.Windows.Forms.Timer, класс System.Timers.Timer по умолчанию вызовет ваш обработчик событий таймера в рабочем потоке, полученном из пула потоков общеязыковой среды выполнения (CLR) . [...] Класс System.Timers.Timer предоставляет простой способ решения этой дилеммы - он предоставляет открытое свойство SynchronizingObject. Установка этого свойства для экземпляра формы Windows (или элемента управления в форме Windows) будет убедитесь, что код вашего обработчика событий Elapsed выполняется в том же потоке, в котором был создан экземпляр SynchronizingObject. "
Мико
7
Согласно разделу потокобезопасности в Threading.Timer«ю.ш. статье MSDN , это совершенно поточно- ...
Питер
62
System.Threading.Timer"по иронии судьбы" не потокобезопасен, как System.Threading.Threadи потоки, полученные через пул lockТот факт, что эти классы не держат вас в руках и управляют использованием самого ключевого слова, не означает, что эти классы не являются поточно-ориентированными. Вы могли бы также сказать System.Threading.Thread, что это не потокобезопасность, потому что это так же верно.
Кирк Волл
8
Также интервал System.Timer.Timer может быть только Int32. Интервал System.Threading.Timer может быть до Int64
Brent
11
К сожалению, этот крайне вводящий в заблуждение (в лучшем случае) ответ принят и так высоко оценен. Единственное существенное утверждение в самом ответе просто неверно. SynchronizingObjectНе делает объект таймера сам поточно-. Это просто гарантирует, что ваш код для обработки события таймера вызывается в определенном потоке (если вы установите это свойство соответствующим образом). Сам объект таймера не гарантированно является потокобезопасным, как четко указано в документации. С другой стороны, System.Threading.Timerобъект является конкретно документирован как потокобезопасной.
Петер Дунихо
169

System.Threading.Timerпростой таймер. Он вызывает вас обратно в поток пула потоков (из рабочего пула).

System.Timers.Timerэто System.ComponentModel.Componentобертка System.Threading.Timer, и предоставляет некоторые дополнительные функции, используемые для диспетчеризации в определенном потоке.

System.Windows.Forms.Timerвместо этого оборачивает собственный HWND только для сообщений и использует таймеры окон, чтобы вызывать события в этом цикле сообщений HWND.

Если ваше приложение не имеет пользовательского интерфейса и вам нужен самый легкий и универсальный таймер .Net, возможный (потому что вы счастливы, вычисляя свою собственную многопоточность / диспетчеризацию), то System.Threading.Timerон так же хорош, как и в рамках.

Я не до конца понимаю, с чем System.Threading.Timerсвязаны проблемы «не безопасных потоков» . Возможно, это то же самое, что задано в этом вопросе: Потоковая безопасность System.Timers.Timer против System.Threading.Timer , или, возможно, каждый просто означает, что:

  1. Легко писать условия гонки, когда вы используете таймеры. Например, смотрите этот вопрос: Таймер (System.Threading) поток безопасности

  2. повторный вход уведомлений таймера, когда ваше событие таймера может вызвать и перезвонить вам во второй раз, прежде чем вы закончите обработку первого события. Например, посмотрите на этот вопрос: поточно-ориентированное выполнение с использованием System.Threading.Timer и Monitor.

Тим Ловелл-Смит
источник
Правда System.Timers.Timerиспользует System.Threading.Timerвнутренне. Смотрите исходный код .
августа
120

В своей книге « CLR Via C # » Джефф Ритчер не рекомендует использовать System.Timers.Timerэтот таймер System.ComponentModel.Component, что позволяет использовать его в области разработки Visual Studio. Так что это было бы полезно, только если вы хотите, чтобы таймер на поверхности дизайна.

Он предпочитает использовать System.Threading.Timerдля фоновых задач в потоке пула потоков.

герой
источник
36
Его можно использовать на поверхности дизайна - это не значит, что так и должно быть, и от этого не будет вредных последствий. Читая статью в предыдущем ответе на этот вопрос, Timers.Timer кажется гораздо более предпочтительным, чем Threading.Timer.
Стивен Дрю
6
Ну, что предпочтительнее, зависит от контекста, верно? Насколько я понимаю, System.Threading.Timer выполняет переданный обратный вызов в новом рабочем потоке из ThreadPool. Что, я полагаю, также является причиной того, что это не обязательно потокобезопасно. В некотором смысле имеет смысл. Так что, теоретически, вам не придется беспокоиться о том, как раскрутить собственный рабочий поток, так как этот таймер сделает это за вас. Вид, кажется, смехотворно полезным.
Финстер
6
Использование System.Threading.Timerпохоже на использование пула потоков или создание собственного потока. Из Конечно , эти классы не обрабатывают синхронизацию для вас - это ваша работа! Ни поток пула потоков, ни ваш собственный поток, ни обратный вызов таймера не будут обрабатывать блокировку - для какого объекта и каким образом и при каких обстоятельствах вам нужно блокировать, требуется здравый смысл, а многопоточная версия таймера дает вам большую гибкость и зернистость.
Кирк Волл
2
-1 этот ответ с самого начала субъективен или самоуверен и не дает конкретной информации о том, почему System.Threading.Timer предпочитает Джефф Ритчер
Брайан Огден
42

Информация от Microsoft об этом (см. Замечания по MSDN ):

  • System.Timers.Timer , который запускает событие и выполняет код в одном или нескольких приемниках событий через равные промежутки времени. Класс предназначен для использования в качестве серверного или сервисного компонента в многопоточной среде; он не имеет пользовательского интерфейса и не виден во время выполнения.
  • System.Threading.Timer , который выполняет единственный метод обратного вызова в потоке пула потоков через равные промежутки времени. Метод обратного вызова определяется, когда создается таймер, и его нельзя изменить. Как и класс System.Timers.Timer, этот класс предназначен для использования в качестве серверного или служебного компонента в многопоточной среде; он не имеет пользовательского интерфейса и не виден во время выполнения.
  • System.Windows.Forms.Timer (только .NET Framework), компонент Windows Forms, который запускает событие и выполняет код в одном или нескольких приемниках событий через равные промежутки времени. Компонент не имеет пользовательского интерфейса и предназначен для использования в однопоточной среде; он выполняется в потоке пользовательского интерфейса.
  • System.Web.UI.Timer (только .NET Framework), компонент ASP.NET, который выполняет асинхронную или синхронную обратную передачу веб-страниц с регулярным интервалом.

Интересно отметить, что System.Timers.Timerон устарел в .NET Core 1.0, но был снова реализован в .NET Core 2.0 (/ .NET Standard 2.0). Цель .NET Standard 2.0 состояла в том, чтобы было как можно проще перейти с .NET Framework, что, вероятно, стало причиной его возвращения.

Когда он устарел, вместо него рекомендуется использовать надстройку анализатора переносимости .NET Visual StudioSystem.Threading.Timer .

Похоже, что Microsoft предпочитает System.Threading.Timerраньше System.Timers.Timer.

РЕДАКТИРОВАТЬ ПРИМЕЧАНИЕ 2018-11-15: я передаю свой ответ, так как старая информация о .NET Core 1.0 больше не действительна.

ice1e0
источник
2
Кажется, это правда: github.com/npgsql/npgsql/issues/471#issuecomment-94104090
Марко Сулла,
@Taegost, его использование также ограничено - см. MSDN msdn.microsoft.com/en-us/library/… и прочитайте замечания о доступности платформы.
astrowalker
@astrowalker - Спасибо за это, в то время, когда я сделал комментарий, этот ответ почти не содержал подробностей. Поскольку теперь в нем есть детали, о которых я спрашивал, я удалил свой комментарий.
Taegost
1
System.Timers.Timer теперь поддерживается в .NET Standard 2.0 и .NET Core 2.0 и выше. docs.microsoft.com/en-us/dotnet/api/system.timers.timer (прокрутить до конца статьи)
Ли Гриссом,
Существует также System.Windows.Threading.DispatcherTimer для этого ответа .
SpeedCoder5
39

Одно важное отличие, не упомянутое выше, которое может вас поймать, заключается в том, что System.Timers.Timerмолча проглатывает исключения, а System.Threading.Timerне делает.

Например:

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

против

var timer = new System.Threading.Timer(x =>
{
    var z = 0;
    var i = 1 / z;
}, null, 0, Timeout.Infinite);
stovroz
источник
1
Недавно я решил эту проблему с Timers.Timer, и это было очень больно ... Есть идеи, как мне переписать с Threading.Timer? stackoverflow.com/questions/41618324/…
Тез Уингфилд
7
В исходном коде есть пустая загвоздка. См. Исходный код System.Timers.Timer здесь
stomy
Омгш, почему программисты MS не способны делать одно и то же на самом деле одно и то же?
xmedeko
2
Пример не объясняет, как один глотает исключения, а другой нет. Может кто-нибудь, пожалуйста, заполните детали?
Шон
24

Я нашел краткое сравнение с MSDN

Библиотека классов .NET Framework включает четыре класса с именем Timer, каждый из которых предлагает различные функции:

System.Timers.Timer, который запускает событие и выполняет код в одном или нескольких приемниках событий через равные промежутки времени. Класс предназначен для использования в качестве серверного или сервисного компонента в многопоточной среде; он не имеет пользовательского интерфейса и не виден во время выполнения.

System.Threading.Timer, который выполняет один метод обратного вызова в потоке пула потоков через равные промежутки времени. Метод обратного вызова определяется, когда создается таймер, и его нельзя изменить. Как и класс System.Timers.Timer, этот класс предназначен для использования в качестве серверного или служебного компонента в многопоточной среде; он не имеет пользовательского интерфейса и не виден во время выполнения.

System.Windows.Forms.Timerкомпонент Windows Forms, который запускает событие и выполняет код в одном или нескольких приемниках событий через равные промежутки времени. Компонент не имеет пользовательского интерфейса и предназначен для использования в однопоточной среде.

System.Web.UI.Timerкомпонент ASP.NET, который выполняет асинхронную или синхронную обратную передачу веб-страниц с регулярным интервалом.

По умолчанию
источник
1

Эти два класса функционально эквивалентны, за исключением того, что System.Timers.Timerимеет возможность вызывать все свои обратные вызовы истечения таймера через ISynchronizeInvoke , устанавливая SynchronizingObject . В противном случае оба таймера вызывают обратные вызовы с истечением срока действия в потоках пула потоков.

Когда вы перетаскиваете объект System.Timers.Timerна поверхность конструктора Windows Forms, Visual Studio устанавливает SynchronizingObject для объекта формы, что приводит к вызову всех обратных вызовов с истечением срока действия в потоке пользовательского интерфейса.

Эдвард Брей
источник
1

Из MSDN: System.Threading.Timerэто простой, легкий таймер, который использует методы обратного вызова и обслуживается потоками пула потоков. Это не рекомендуется для использования с Windows Forms, потому что его обратные вызовы не происходят в потоке пользовательского интерфейса. System.Windows.Forms.Timerэто лучший выбор для использования с Windows Forms. Для серверных функций таймера, вы можете рассмотреть возможность использования System.Timers.Timer, которое вызывает события и имеет дополнительные функции.

Источник

Грег Гам
источник