Альтернативы Thread.Sleep ()

Каждые N минут мы хотим выполнить список задач. Итак, мы создали исполнителя задачи с

do { DoWork(); }while(!stopRequested) 

Теперь мы хотим иметь паузу между рабочими циклами. Кажется, все думают, что Thread.Sleep () – это дьявол. Я видел упоминание использования материалов Monitor / Event, но у нас нет кого-то, кто говорит нам делать работу. Мы просто хотим делать вещи каждые N минут, как часы.

Так есть альтернатива или я нашел правильное использование Thread.Sleep?

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

Ссылка на объект требуется для нестатического поля, метода или свойства «System.Threading.WaitHandle.WaitOne (System.TimeSpan)»

WaitHandle , вы должны называть WaitOne на WaitHandle . Это метод экземпляра. В противном случае, как бы он знал, чего ждать?

Определенно лучше иметь что-то , на что вы можете реагировать, вместо сна, чтобы вы могли заметить отмену без ожидания минут без причины. Другой альтернативой WaitHandle является использование Monitor.Wait / Pulse .

Однако, если вы используете .NET 4, я бы посмотрел, что предлагает параллельная библиотека задач … он немного выше, чем другие, и, как правило, хорошо продуманная библиотека.

Для обычных рабочих задач вам может понадобиться использовать Timer (либо System.Threading.Timer либо System.Timers.Timer ), либо, возможно, даже Quartz.NET .

По моему мнению, Thread.Sleep () плохо, потому что он вытесняет ресурсы streamа из кеша, поэтому их нужно снова загружать. Неважно, но это может усугубить проблемы с производительностью в ситуациях с высокой нагрузкой. И тогда есть факт, что время не точное, и что он эффективно не может ждать длительности около 10 мс …

Я использую этот fragment:

 new System.Threading.ManualResetEvent(false).WaitOne(1000); 

Легко, как пирог, и все это подходит на одной линии. Создает новый обработчик событий, который никогда не будет установлен, а затем ждет полный период таймаута, который вы укажете в качестве аргумента для WaitOne() .

Хотя для этого конкретного сценария Таймер, вероятно, будет более подходящим подходом:

 var workTimer = new System.Threading.Timer( (x) => DoWork(), null, 1000, // initial wait period 300000); // subsequent wait period 

Затем вместо установки переменной отмены вы остановите таймер с помощью workTimer.Stop() .


Изменить :

Поскольку люди все еще находят это полезным, я должен добавить, что .NET 4.5 представляет метод Task.Delay , который еще более краток и также поддерживает async:

 Task.Delay(2000).Wait(); // Wait 2 seconds with blocking await Task.Delay(2000); // Wait 2 seconds without blocking 

Thread.Sleep – это не дьявол – вы можете использовать его для такого сценария. Это просто не очень надежно для коротких периодов времени.

Использование WaitHandle – хороший вариант, но вам нужен конкретный экземпляр дескриптора ожидания. Однако это не будет сделано в одиночку.

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

Три варианта, которые я могу придумать с головы:

  • System.Threading.Timer ( Подробнее … )
  • Monitor.Wait ( Подробнее … )
  • System.Timers.Timer ( Подробнее … )

но я уверен, что многие упомянут – Thread.Sleep() не так уж плох.

Вы можете использовать ManualResetEvent, который вы установите, когда пришло время остановиться, а затем на нем WaitOne.

Я бы использовал таймер ожидания, который сигнализирует AutoResetEvent. Ваш stream должен ждать этого объекта WaitHandle. Вот небольшое консольное приложение, демонстрирующее такой подход:

 class Program { const int TimerPeriod = 5; static System.Threading.Timer timer; static AutoResetEvent ev; static void Main(string[] args) { ThreadStart start = new ThreadStart(SomeThreadMethod); Thread thr = new Thread(start); thr.Name = "background"; thr.IsBackground = true; ev = new AutoResetEvent(false); timer = new System.Threading.Timer( Timer_TimerCallback, ev, TimeSpan.FromSeconds(TimerPeriod), TimeSpan.Zero); thr.Start(); Console.WriteLine(string.Format("Timer started at {0}", DateTime.Now)); Console.ReadLine(); } static void Timer_TimerCallback(object state) { AutoResetEvent ev = state as AutoResetEvent; Console.WriteLine(string.Format ("Timer's callback method is executed at {0}, Thread: ", new object[] { DateTime.Now, Thread.CurrentThread.Name})); ev.Set(); } static void SomeThreadMethod() { WaitHandle.WaitAll(new WaitHandle[] { ev }); Console.WriteLine(string.Format("Thread is running at {0}", DateTime.Now)); } } 

Если все, что вы делаете, это что-то вроде:

 while (!stop_working) { DoWork(); Thread.Sleep(FiveMinutes); } 

Тогда я бы предложил не использовать нить. Во-первых, нет никаких особых оснований для того, чтобы нанести системный накладной выделенный stream, который проводит большую часть времени. Во-вторых, если вы установите флаг stop_working 30 секунд после того, как stream перестанет спать, вам придется подождать четыре с половиной минуты до того, как stream просыпается и заканчивается.

Я бы предложил, как и другие: использовать таймер:

 System.Threading.Timer WorkTimer; // Somewhere in your initialization: WorkTimer = new System.Threading.Timer((state) => { DoWork(); }, null, TimeSpan.FromMinutes(5.0), TimeSpan.FromMinutes(5.0)); 

И закрыть:

  WorkTimer.Dispose(); 

Вы можете использовать System.Timers.Timer и выполнять работу в своем обработчике.

Как говорили другие ответчики, таймеры могут хорошо работать для вас.

Если вам нужен собственный stream, я бы не использовал Thread.Sleep здесь, хотя бы потому, что, если вам нужно закрыть приложение, нет хорошего способа сказать ему, чтобы он вышел из сна. Раньше я использовал что-то подобное.

 class IntervalWorker { Thread workerThread; ManualResetEventSlim exitHandle = new ManualResetEventSlim(); public IntervalWorker() { this.workerThread = new Thread(this.WorkerThread); this.workerThread.Priority = ThreadPriority.Lowest; this.workerThread.IsBackground = true; } public void Start() { this.workerThread.Start(); } public void Stop() { this.exitHandle.Set(); this.workerThread.Join(); } private void WorkerThread() { int waitTimeMillis = 10000; // first work 10 seconds after startup. while (!exitHandle.Wait(waitTimeMillis)) { DoWork(); waitTimeMillis = 300000; // subsequent work at five minute intervals. } } } 

Я использовал таймер в приложении WinForms, а консольное приложение запускалось периодически с помощью ScheduledTask на сервере. WinForms с таймером использовался в тех случаях, когда я хочу, чтобы он отображал уведомления, которые он запускал, и что он нашел (я установил их для имитации в systray). В ситуациях, когда я хочу получать уведомление только в том случае, если что-то не так на сервере, я разместил их на сервере в качестве консольных приложений и запускал их как запланированные задачи. Кажется, это работает неплохо.

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

Я нашел способ взломать Thread.Sleep , периодически Thread.Sleep , и делайте события, если вам нужно отменить. Смотри ниже:

 // Pay attention every 1/10 sec to maintain some UI responsiveness while (val > 0) { Thread.Sleep(100); val = val - 100; Application.DoEvents(); if (val == x) { // You could do some conditional stuff here at specific times } } 

Замените val с желаемой задержкой в ​​миллисекундах. Чем больше вы понижаете значение Thread.Sleep тем больше будет реагировать программа. Кажется приемлемым для меня 100 мс. Лучше всего 50 мс.

  • Является ли stream операторов ++ безопасным?
  • Конфигурация нитей на основе №. процессорных ядер
  • Как заставить stream Java ждать выхода другого streamа?
  • C ++ 11 представил стандартизованную модель памяти. Что это значит? И как это повлияет на программирование на С ++?
  • Нужно ли защищать доступ для чтения к контейнеру STL в многопоточной среде?
  • Есть ли преимущество использования Синхронизированного метода вместо Синхронизированного блока?
  • Показать прогрессDialog Android
  • C ++ Threads, std :: system_error - операция не разрешена?
  • Если утверждение с сопоставлением строк не выполняется
  • Что такое «streamовое локальное хранилище» в Python и зачем оно мне нужно?
  • Разница между загрузчиком classа контекста streamа и обычным загрузчиком classов
  • Давайте будем гением компьютера.