Alternatives to Thread.Sleep()

后端 未结 11 1209
清歌不尽
清歌不尽 2020-11-27 03:48

Every N minutes we want to run through a list of tasks. So we\'ve created a task executor with a

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

No

相关标签:
11条回答
  • 2020-11-27 04:30

    By my understanding, Thread.Sleep() is bad because it forces the thread's resources out of the cache, so they have to be loaded again afterwards. Not a big deal, but it could aggravate performance issues in high-load situations. And then there's the fact that the timing isn't precise, and that it effectively can't wait for durations under about 10ms...

    I use this snippet:

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

    Easy as pie and it all fits on one line. Creates a new event handler that will never be set, and then waits the full timeout period, which you specify as the argument to WaitOne().

    Although, for this specific scenario, a Timer would probably be a more appropriate approach:

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

    Then, instead of setting a cancel variable, you would stop the timer with workTimer.Stop().


    Edit:

    Since people are still finding this useful, I should add that .NET 4.5 introduces the Task.Delay method, which is even more concise and also supports async:

    Task.Delay(2000).Wait(); // Wait 2 seconds with blocking
    await Task.Delay(2000); // Wait 2 seconds without blocking
    
    0 讨论(0)
  • 2020-11-27 04:30

    I would use a waiting timer which signals an AutoResetEvent. Your thread should wait for this WaitHandle object. Here is a small console app showing this approach:

    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));
        }
    }
    
    0 讨论(0)
  • 2020-11-27 04:34
           try {
                TimeUnit.MILLISECONDS.sleep(1000L);
            } catch (InterruptedException e) {
                // handle
            }
    
    0 讨论(0)
  • 2020-11-27 04:36

    You have to call WaitOne on a WaitHandle, certainly. It's an instance method. Otherwise how would it know what to wait for?

    It's definitely better to have something you can react to instead of sleep, so that you can notice cancellation without waiting minutes for no reason. Another alternative to WaitHandle is to use Monitor.Wait/Pulse.

    However, if you're using .NET 4 I'd look into what the Task Parallel Library has to offer... it's at a slightly higher level than the other options, and is generally a well thought out library.

    For regular work tasks you might want to look at using a Timer (either System.Threading.Timer or System.Timers.Timer) or possibly even Quartz.NET.

    0 讨论(0)
  • 2020-11-27 04:39

    Thread.Sleep isn't the devil - you could use it for a scenario like this. It's just not very reliable for short durations.

    Using a WaitHandle is a good option - but you need a specific instance of a wait handle. It won't do this alone, however.

    That being said, most of the time, operations like this are better suited towards using a Timer. Is there a reason you're trying to process this in a loop rather than just using a Timer to start off the work item?

    0 讨论(0)
提交回复
热议问题