比较使用Thread.Sleep和Timer来延迟执行
我有一个方法应该延迟运行一段指定的时间。
我应该使用
Thread thread = new Thread(() => { Thread.Sleep(millisecond); action(); }); thread.IsBackground = true; thread.Start();
要么
Timer timer = new Timer(o => action(), null, millisecond, -1);
我读过一些关于使用Thread.Sleep的文章是糟糕的devise。 但我不明白为什么。
但是对于使用Timer,Timer的configuration方法。 由于执行延迟,我不知道如何configurationTimer。 你有什么build议吗?
或者,如果您有延迟执行的替代代码也很感激。
谢谢,
一个区别是System.Threading.Timer在线程池线程上调度callback,而不是每次创build一个新的线程。 如果你在应用程序的生命周期中不止一次需要这样做,这将节省创build和销毁一堆线程的开销(这是一个非常耗费资源的过程,正如你参考的文章所指出的那样),因为它会只是在池中重用线程,如果你有一个以上的计时器,那么就意味着你将会有更less的线程同时运行(同时也节省了大量的资源)。
换句话说,Timer将会更有效率。 这也可能是更准确的,因为只要你指定的时间(操作系统可能睡眠更长时间)Thread.Sleep只保证等待至less。 当然,Timer仍然不会完全准确,但意图是尽可能接近指定的时间触发callback,而这不一定是Thread.Sleep的意图。
至于销毁定时器,callback可以接受一个参数,所以你可能能够传递定时器本身作为参数,并在callback中调用Dispose(虽然我没有试过这个 – 我想这可能是定时器可能在callback期间被locking)。
编辑:不,我猜你不能这样做,因为你必须在Timer构造函数本身中指定callback参数。
也许这样? (再次,实际上没有尝试过)
class TimerState { public Timer Timer; }
…并启动计时器:
TimerState state = new TimerState(); lock (state) { state.Timer = new Timer((callbackState) => { action(); lock (callbackState) { callbackState.Timer.Dispose(); } }, state, millisecond, -1); }
在定时器字段被设置之前,locking应该防止定时器callback尝试释放定时器。
附录:正如评论者指出的,如果action()对UI做了某些事情,那么使用System.Windows.Forms.Timer可能是一个更好的select,因为它将在UI线程上运行callback。 但是,如果情况并非如此,那么Thread.Sleep与Threading.Timer就是Threading.Timer。
使用ThreadPool.RegisterWaitForSingleObject
而不是定时器:
//Wait 5 seconds then print out to console. //You can replace AutoResetEvent with a Semaphore or EventWaitHandle if you want to execute the command on those events and/or the timeout System.Threading.ThreadPool.RegisterWaitForSingleObject(new AutoResetEvent(false), (state, bTimeout) => Console.WriteLine(state), "This is my state variable", TimeSpan.FromSeconds(5), true);
我认为Thread.Sleep是好的,如果你真的想暂停应用程序一段指定的时间。 我认为人们说这是一个糟糕的devise的原因是因为在大多数情况下,人们实际上并不希望应用程序暂停。
例如,我正在使用一个pop3客户程序,程序员正在使用Thread.Sleep(1000)等待套接字检索邮件。 在这种情况下,最好将一个事件处理程序挂接到套接字,并在套接字完成后继续执行程序。
我记得实施类似于Eric的解决scheme。 这是一个工作的;)
class OneTimer { // Created by Roy Feintuch 2009 // Basically we wrap a timer object in order to send itself as a context in order to dispose it after the cb invocation finished. This solves the problem of timer being GCed because going out of context public static void DoOneTime(ThreadStart cb, TimeSpan dueTime) { var td = new TimerDisposer(); var timer = new Timer(myTdToKill => { try { cb(); } catch (Exception ex) { Trace.WriteLine(string.Format("[DoOneTime] Error occured while invoking delegate. {0}", ex), "[OneTimer]"); } finally { ((TimerDisposer)myTdToKill).InternalTimer.Dispose(); } }, td, dueTime, TimeSpan.FromMilliseconds(-1)); td.InternalTimer = timer; } } class TimerDisposer { public Timer InternalTimer { get; set; } }
我在System.Timer中唯一的缺点是大部分时间我都看到它在轮询服务中使用了很长时间(小时,几分钟),开发人员经常忘记在启动计时器之前启动事件。 这意味着,如果我启动应用程序或服务,我必须等到计时器(小时,分钟)才真正执行。
当然,这不是定时器的问题,但我认为它经常使用不当,因为它太容易误用了。
@miniscalope不要使用ThreadPool.RegisterWaitForSingleObject而不是定时器,System.Threading.Timer会在一个线程池线程上排队一个callback,以等待时间已经过去,并且不需要等待处理,等待单个对象会绑定一个线程池线程,等待事件发出信号,或超时在线程调用callback之前过期。