Насколько масштабируем System.Threading.Timer? - PullRequest
26 голосов
/ 28 августа 2008

Я пишу приложение, в котором нужно будет использовать Timer s, но потенциально их очень много. Насколько масштабируем класс System.Threading.Timer? Документация просто говорит, что она «легковесная», но не объясняет дальше. Эти таймеры засасываются в один поток (или очень маленький пул потоков), который обрабатывает все обратные вызовы от имени Timer, или каждый Timer имеет свой собственный поток?

Я думаю, что еще один способ перефразировать вопрос: как реализуется System.Threading.Timer?

Ответы [ 4 ]

29 голосов
/ 28 августа 2008

Я говорю это в ответ на множество вопросов: не забывайте, что (управляемый) исходный код платформы доступен. Вы можете использовать этот инструмент, чтобы получить все это: http://www.codeplex.com/NetMassDownloader

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

Хотя они определенно используют потоки пула, а не поток по таймеру.

Стандартный способ реализовать большую коллекцию таймеров (как ядро ​​делает это внутренне, и я подозреваю, косвенно, как заканчивается ваша большая коллекция таймеров) - поддерживать список, отсортированный по времени до истечения срока действия. - поэтому система должна беспокоиться только о проверке следующего таймера, который истекает, а не весь список.

Грубо говоря, это дает O (log n) для запуска таймера и O (1) для обработки запущенных таймеров.

Редактировать: Просто искал в книге Джеффа Рихтера. Он говорит (о Threading.Timer), что он использует один поток для всех объектов Timer, этот поток знает, когда должен быть установлен следующий таймер (то есть, как указано выше), и вызывает ThreadPool.QueueUserWorkItem для соответствующих обратных вызовов. Это приводит к тому, что если вы не завершите обслуживание одного обратного вызова по таймеру до наступления следующего, ваш обратный вызов будет повторно введен в другой поток пула. Итак, в заключение, я сомневаюсь, что вы столкнетесь с большой проблемой, связанной с большим количеством таймеров, но вы можете испытать истощение пула потоков, если большое количество из них запускается с одним и тем же таймером и / или их обратные вызовы работают медленно.

7 голосов
/ 28 августа 2008

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

Вот хорошая статья из журнала MSDN, опубликованная несколько лет назад, которая сравнивает три доступных класса таймеров и дает некоторое представление об их реализации:

http://msdn.microsoft.com/en-us/magazine/cc164015.aspx

5 голосов
/ 28 августа 2008

Объедините их. Создать таймер обслуживание и спросите это для таймеров. Нужно будет только 1 активный таймер (для следующего звонка) ...

Чтобы это было лучше, чем просто создание большого количества объектов Threading.Timer, вы должны предположить, что это не совсем то, что Threading.Timer уже делает внутри. Мне было бы интересно узнать, как вы пришли к такому выводу (я не разбирал нативные части фреймворка, поэтому вы вполне могли бы быть правы).

0 голосов
/ 28 августа 2008

^^ как говорит DannySmurf: объедините их. Создайте службу таймера и спросите это для таймеров. Потребуется только сохранить 1 активный таймер (для следующего соответствующего вызова) и историю всех запросов таймера и пересчитать это по AddTimer () / RemoveTimer ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...