Достаточно ли эффективен System.Threading.Timer для тысяч одновременных таймеров?
Автор вопроса: Jeff CyrОтветов: 5
Я работаю над механизмом тайм-аута запроса. Мой первоначальный подход состоял в том, чтобы создать один System.Threading.Timer для каждого запроса. Количество одновременных запросов может достигать тысяч.
Мне интересно, должен ли я вместо этого создать TimeoutScheduler, который будет внутренне использовать только один таймер вместо одного для каждого запроса.
Может ли кто-нибудь, кто знает внутренности System.Threading.Timer, дать мне некоторое представление о том, будет ли TimeoutScheduler хорошей идеей или он только попытается оптимизировать что-то уже достаточно эффективное.
Примечание. Для моего сценария точность таймера не важна.
(Я провел тест производительности с помощью System.Threading.Timer с множеством одновременных таймеров. Казалось, он хорошо масштабируется, но я не уверен, что это окажет нежелательное давление на реальную систему)
Технически нет никаких проблем с созданием их тысяч. Просто имейте в виду, что они используют глобальные системные ресурсы, поэтому вы в конце концов достигнете верхнего предела и/или начнете голодать другие программы (включая саму Windows), если сойдете с ума.
Также убедитесь, что вы утилизируете таймеры, когда закончите с ними, иначе вы столкнетесь с огромной утечкой ресурсов.
Я должен сказать, что это похоже на то, что вы могли бы реализовать с помощью одного таймера; просто поддерживайте словарь активных запросов и тайм-аутов, и на каждом тике просматривайте весь словарь и проверяйте каждую запись. Вы можете улучшить производительность, сделав его отсортированным списком; таким образом, если в течение следующих 5 минут ничего не истекло, метод тика завершится после просмотра первой записи.
В дополнение к вышесказанному вы также можете динамически настроить интервал тактов, чтобы он срабатывал всякий раз, когда следующий запрос запланирован на истечение времени ожидания; затем на каждом тике перепланируйте следующий тик на следующий тайм-аут. Это практически не потребует системных ресурсов (только один таймер), а также будет очень быстрым (как и в случае с вашей идеей с одним таймером на запрос, вы будете запускать дорогостоящий код только тогда, когда запросы действительно истекают).
Несмотря на то, что вы можете создать тысячи таймеров, описанный выше подход будет намного лучше масштабироваться, а также его будет намного проще тестировать и поддерживать.
Ответ 2 · рейтинг 1 · Wiseheathen
Планировщик времени ожидания - хорошая идея, но таймеры имеют самый низкий приоритет выполнения. Если это для планирования тайм-аута, самым надежным вариантом будет поток, который отслеживает тайм-ауты других потоков и обновления с помощью QueryPerormanceCounter и QueryPerformanceFrequency. Это будет блокирующий класс, но внутри их собственного потока это не будет иметь значения. Вы также можете рассмотреть возможность запуска планировщика времени ожидания с более высоким приоритетом.
Ответ 3 · рейтинг 1 · ParmesanCodice
System.Threading.Timer выполняет свой TimerCallback в ThreadPool, создание 1000 может привести к голоданию пула потоков.
Используйте делегат TimerCallback, чтобы указать метод, который должен выполнять таймер. Делегат таймера указывается при создании таймера и не может быть изменен. Метод не выполняется в потоке, создавшем таймер; он выполняется в потоке ThreadPool, предоставленном системой.
System.Timers.Timer ведет себя точно так же. TimeoutScheduler - это то, что нужно.
Ответ 4 · рейтинг 1 · Gusman
Я знаю, что это старо, но эти ответы противоречат тому, что я всегда делал, поэтому я проверил справочный источник, и все они неверны.
Нет никакой проблемы в создании тысяч таймеров, внутри все таймеры работают в системе очередь таймеров, они не создают системные таймеры, эта очередь обрабатывается одним потоком, поэтому единственный выделенный ресурс - это дескриптор ожидания для каждого таймера, и они действительно легкие.