Альтернативы Thread.Sleep ()
Каждые N минут мы хотим выполнить список задач. Итак, мы создали исполнителя задачи с
do { DoWork(); }while(!stopRequested)
Теперь мы хотим иметь паузу между рабочими циклами. Кажется, все думают, что Thread.Sleep () – это дьявол. Я видел упоминание использования материалов Monitor / Event, но у нас нет кого-то, кто говорит нам делать работу. Мы просто хотим делать вещи каждые N минут, как часы.
Так есть альтернатива или я нашел правильное использование Thread.Sleep?
- Java: Как остановить stream?
- Обновление Force GUI из UI Thread
- Redis + ActionController :: Живые streamи не умирают
- Выполнение функции в фоновом режиме при использовании ограниченного количества ядер / streamов и очереди дополнительных исполнений?
- Когда следует использовать ключевое слово volatile в C #?
Кто-то из другого сообщения упоминал WaitHandle.WaitOne () как альтернативу, но вы не можете назвать это по нестационарному методу, по-видимому? Или, по крайней мере, я не могу, потому что получаю ошибку времени компиляции ..
Ссылка на объект требуется для нестатического поля, метода или свойства «System.Threading.WaitHandle.WaitOne (System.TimeSpan)»
- C ++ 0x прерывание streamа
- Выполняются ли одновременно два синхронизированных метода
- Доступ к интерфейсу пользовательского интерфейса (Main) безопасно в WPF
- Автоматизация кода кода InvokeRequired
- Когда основной stream останавливается в Java?
- Ошибка при использовании Task.Factory
- Разница между изменчивой и синхронизированной в Java
- Неверная операция кросс-streamов: управление осуществляется из streamа, отличного от streamа, который был создан на
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 мс.