Thread.Sleep()的替代方法
每隔N分钟我们就要运行一个任务列表。 所以我们创build了一个任务执行器
do { DoWork(); }while(!stopRequested)
现在我们想在工作周期之间暂停一下。 每个人似乎都认为Thread.Sleep()是魔鬼。 我已经看到提及使用监视/事件的东西,但我们没有其他人告诉我们去做工作。 我们只是想每隔N分钟就像发条一样做东西。
那么有没有其他的select,或者我find了Thread.Sleep的有效使用?
在另一篇文章中有人提到WaitHandle.WaitOne()作为替代,但你不能从一个非静态方法显然调用? 或者至less我不能,因为我得到一个编译时间错误..
非静态字段,方法或属性“System.Threading.WaitHandle.WaitOne(System.TimeSpan)”需要对象引用
当然,你必须在 WaitHandle
上调用WaitOne
。 这是一个实例方法。 否则,它会如何知道等待什么?
拥有一些可以反应而不是睡眠的东西肯定会更好,所以你可以注意到无需等待几分钟就取消了。 WaitHandle
另一种替代方法是使用Monitor.Wait
/ Pulse
。
但是,如果你使用的是.NET 4,我会研究任务并行库提供的function…它比其他选项稍高一些,通常是一个深思熟虑的库。
对于常规工作任务,您可能需要使用Timer
( System.Threading.Timer
或System.Timers.Timer
)或甚至Quartz.NET 。
根据我的理解,Thread.Sleep()是不好的,因为它强制线程的资源超出caching,所以他们必须在之后再次加载。 没有什么大不了的,但是它可能会在高负载情况下加剧性能问题。 然后有一个事实,即时间不精确,并且它实际上不能等待大约10ms以下的持续时间。
我使用这个片段:
new System.Threading.ManualResetEvent(false).WaitOne(1000);
容易馅饼,它都适合在一条线上。 创build一个永远不会被设置的新事件处理程序,然后等待您指定为WaitOne()
的参数的完整超时时间。
虽然,对于这个特定的场景,一个Timer可能是一个更合适的方法:
var workTimer = new System.Threading.Timer( (x) => DoWork(), null, 1000, // initial wait period 300000); // subsequent wait period
然后,而不是设置取消variables,您将停止与workTimer.Stop()
计时器。
编辑 :
由于人们仍然觉得这很有用,所以我应该补充一点,.NET 4.5引入了Task.Delay方法,这个方法更加简洁,也支持asynchronous:
Task.Delay(2000).Wait(); // Wait 2 seconds with blocking await Task.Delay(2000); // Wait 2 seconds without blocking
Thread.Sleep
不是魔鬼 – 你可以用它Thread.Sleep
这样的场景。 短时间内不太可靠。
使用WaitHandle是一个不错的select – 但是你需要一个等待句柄的特定实例。 但是,这不会单独做到这一点。
话虽如此,大多数时候,像这样的操作更适合使用定时器。 是否有一个原因,你试图在循环中处理这个,而不是只使用一个计时器来启动工作项目?
我能想到的三个选项是:
-
System.Threading.Timer
( 更多… ) -
Monitor.Wait
( 更多… ) -
System.Timers.Timer
( 更多… )
但我相信很多人会提到 – Thread.Sleep()
并不是那么糟糕。
您可以使用您在停止时设置的ManualResetEvent,然后在其上执行一个WaitOne。
我会用一个等待计时器来发出一个AutoResetEvent的信号。 你的线程应该等待这个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); }
那么我会build议不要使用线程。 首先,没有什么特别好的理由引起花费大部分时间睡眠的专用线程的系统开销。 其次,如果在线程停止睡眠30秒后设置stop_working
标志,则必须等待四分半钟才能唤醒并终止线程。
我build议像其他人一样:使用计时器:
System.Threading.Timer WorkTimer; // Somewhere in your initialization: WorkTimer = new System.Threading.Timer((state) => { DoWork(); }, null, TimeSpan.FromMinutes(5.0), TimeSpan.FromMinutes(5.0));
并closures:
WorkTimer.Dispose();
你可以使用一个System.Timers.Timer并在其过去的处理程序中执行该工作。
正如其他答复者所说,定时器可能适合你。
如果你真的想要自己的线程,我不会在这里使用Thread.Sleep,如果只是因为如果你需要closures应用程序,没有好办法告诉它退出睡眠。 我以前用过这样的东西。
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应用程序中使用了Timer,并且在服务器上通过ScheduledTask定期启动了一个控制台应用程序。 有一个计时器的WinForms已被用于我希望它popup它运行的通知和它发现的(我已经设置这些以模仿到系统托盘)通知的情况下。 对于我只想在服务器出现问题时收到通知的情况,我将它们作为控制台应用程序放在服务器上,并按计划任务运行。 这似乎工作得很好。
我想我尝试在现在使用定时器的应用程序中使用睡眠,而不喜欢结果。 首先,使用定时器,我可以非常容易地调用最小化的应用程序,以设置或更改前面的设置。 如果应用程序已经睡着了,那么您在睡眠时就很难重新获得访问权限。