Использование сравнения таймера секундомера и даты и времени каждые 1 секунду?

#c# #performance #optimization #.net-core #stopwatch

#c# #Производительность #оптимизация #.net-ядро #секундомер

Вопрос:

Представьте, что у нас есть выделенный поток операционной системы, который должен что-то делать каждые 4,30 минуты.

Вы не можете приостановить поток, потому что ему нужно проверять / выполнять другие действия, и вы не можете использовать await / async, потому что это приведет к выпадению команды из выделенного потока ОС, что приведет к отказу от цели ее первого создания.

Чтобы решить вышеуказанную проблему, я нашел 2 решения:

  • Используется System.Diagnostics.Stopwatch для запуска нового Stopwatch объекта и сравнения его каждые 1 секунду, если он достиг желаемого временного интервала: if (timer.ElapsedMilliseconds == 258000) { ...}
  • Используется System.DateTime для инициализации DateTime объекта DateTime.UtcNow.AddMinutes(4.30) и сравнения его с текущей датой каждые 1 секунду: if (DateTime.UtcNow >= initializedDate) { ... }

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

Второй подход использует много DateTime объектов. Каждую 1 секунду мы будем создавать новый DateTime объект с текущей датой.

Комментарии:

1. Это зависит от точности, которая вам нужна для 4,30 минут. Опрос менее точен, чем событие таймера.

2. @jdweng Точность не требуется, если только цель не отключена на полминуты.

3. Вы можете заставить поток ждать в очереди блокировки и отправлять элемент по таймеру каждые 4,5 минуты… ? Просто идея. Или установите AutoResetEvent …

4. @Fildor это хорошая идея, но System.Threading.Timer использует поток ThreadPool, который я бы не хотел задействовать. Причина, по которой я уже использую выделенный поток, заключается в том, чтобы избежать использования пула потоков.

5. Observable.Interval(TimeSpan.FromMinutes(4.5)).ObserveOn(SynchronizationContext.Current).Subscribe(x => { /* Do stuff here */});

Ответ №1:

Два решения эквивалентны, если вы не хотите очень высокой точности: Stopwatch будет использовать высокоточный системный таймер, если он доступен, и вернется к DateTime нему, если нет. Для решения ваших проблем:

  1. Stopwatch не использует отдельный поток. Он просто считывает системные тики (с высокой или низкой точностью) и выполняет для вас некоторую математику.

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

Я бы использовал Stopwatch , потому что это дает мне прошедшее время бесплатно. 🙂

Комментарии:

1. Стоит отметить, что использование либо Stopwatch и DateTime свяжет поток и, следовательно, будет неэффективным. Использование таймера позволяет коду использовать операционную систему и, следовательно, намного эффективнее.

2. @Enigmativity как бы вы тогда избежали их использования, не делегируя работу другим потокам, таким как потоки пула потоков? Мы делаем все это из выделенного потока.

3. @SpiritBob — Что плохого в использовании другого потока для передачи данных в текущий поток. Перекачка сообщений Windows Forms работает таким образом при вызове Control.Invoke .

4. @Enigmativity ничего плохого, если только вы намеренно не создали выделенный поток для выполнения некоторой работы. В идеале, он не должен делегировать свою работу другим потокам — в этом смысле это противоречит цели создания выделенного потока. В этом случае вам лучше ожидать задачи.

5. @SpiritBob — Я предлагаю намеренно создать поток для планирования работы с исходным выделенным потоком.