#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
нему, если нет. Для решения ваших проблем:
-
Stopwatch
не использует отдельный поток. Он просто считывает системные тики (с высокой или низкой точностью) и выполняет для вас некоторую математику. -
DateTime
является ли структура так, что создание нового экземпляра каждую секунду должно быть дешевым и оказывать нулевое давление на GC.
Я бы использовал Stopwatch
, потому что это дает мне прошедшее время бесплатно.
Комментарии:
1. Стоит отметить, что использование либо
Stopwatch
иDateTime
свяжет поток и, следовательно, будет неэффективным. Использование таймера позволяет коду использовать операционную систему и, следовательно, намного эффективнее.2. @Enigmativity как бы вы тогда избежали их использования, не делегируя работу другим потокам, таким как потоки пула потоков? Мы делаем все это из выделенного потока.
3. @SpiritBob — Что плохого в использовании другого потока для передачи данных в текущий поток. Перекачка сообщений Windows Forms работает таким образом при вызове
Control.Invoke
.4. @Enigmativity ничего плохого, если только вы намеренно не создали выделенный поток для выполнения некоторой работы. В идеале, он не должен делегировать свою работу другим потокам — в этом смысле это противоречит цели создания выделенного потока. В этом случае вам лучше ожидать задачи.
5. @SpiritBob — Я предлагаю намеренно создать поток для планирования работы с исходным выделенным потоком.