比较使用 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
是糟糕的设计。 但我真的不明白为什么。
但是,对于使用Timer
,Timer
有一个dispose方法。 由于执行被延迟,我不知道如何处理Timer
。 你有什么建议吗?
或者,如果您有延迟代码执行的替代建议,我们也将不胜感激。
I have a method which should be delayed from running for a specified amount of time.
Should I use
Thread thread = new Thread(() => {
Thread.Sleep(millisecond);
action();
});
thread.IsBackground = true;
thread.Start();
Or
Timer timer = new Timer(o => action(), null, millisecond, -1);
I had read some articles about how using Thread.Sleep
is bad design. But I don't really understand why.
However, for using Timer
, Timer
has a dispose method. Since the execution is delayed, I don't know how to dispose the Timer
. Do you have any suggestions?
Or, if you have an alternative suggestion for delaying code execution, that would also be appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
一个区别是 System.Threading.Timer 在线程池线程上分派回调,而不是每次都创建一个新线程。 如果您需要在应用程序的生命周期中多次发生这种情况,这将节省创建和销毁一堆线程的开销(正如您引用的文章指出的那样,这是一个非常资源密集型的进程),因为它将只需重用池中的线程,如果您同时运行多个计时器,则意味着同时运行的线程会更少(也节省了大量资源)。
换句话说,
Timer
将会更加高效。 它也可能更准确,因为 Thread.Sleep 只能保证至少等待您指定的时间(操作系统可能会使其休眠更长时间)。 当然,Timer 仍然不会完全准确,但其目的是尽可能接近指定时间触发回调,而这不一定是 Thread.Sleep 的目的。至于销毁
Timer
,回调可以接受一个参数,因此您可以将Timer
本身作为参数传递,并在回调中调用Dispose(尽管我没有没有尝试过这个——我想计时器可能在回调期间被锁定)。编辑:不,我想你不能这样做,因为你必须在 Timer 构造函数本身中指定回调参数。
也许是这样的? (同样,还没有真正尝试过)
...并启动计时器:
锁定应该防止计时器回调在设置
Timer
字段之前尝试释放计时器。附录:正如评论者所指出的,如果
action()
对 UI 做了一些事情,那么使用System.Windows.Forms.Timer
可能是一个更好的选择,因为它将在 UI 线程上运行回调。 但是,如果情况并非如此,并且取决于Thread.Sleep
与Threading.Timer
,则Threading.Timer
是去。One difference is that
System.Threading.Timer
dispatches the callback on a thread pool thread, rather than creating a new thread every time. If you need this to happen more than once during the life of your application, this will save the overhead of creating and destroying a bunch of threads (a process which is very resource intensive, as the article you reference points out), since it will just reuse threads in the pool, and if you will have more than one timer going at once it means you will have fewer threads running at once (also saving considerable resources).In other words,
Timer
is going to be much more efficient. It also may be more accurate, sinceThread.Sleep
is only guaranteed to wait at LEAST as long as the amount of time you specify (the OS may put it to sleep for much longer). Granted,Timer
is still not going to be exactly accurate, but the intent is to fire the callback as close to the specified time as possible, whereas this is NOT necessarily the intent ofThread.Sleep
.As for destroying the
Timer
, the callback can accept a parameter, so you may be able to pass theTimer
itself as the parameter and call Dispose in the callback (though I haven't tried this -- I guess it is possible that the Timer might be locked during the callback).Edit: No, I guess you can't do this, since you have to specify the callback parameter in the
Timer
constructor itself.Maybe something like this? (Again, haven't actually tried it)
...and to start the timer:
The locking should prevent the timer callback from trying to free the timer prior to the
Timer
field having been set.Addendum: As the commenter pointed out, if
action()
does something with the UI, then using aSystem.Windows.Forms.Timer
is probably a better bet, since it will run the callback on the UI thread. However, if this is not the case, and it's down toThread.Sleep
vs.Threading.Timer
,Threading.Timer
is the way to go.@miniscalope 不,不要使用 ThreadPool.RegisterWaitForSingleObject 而不是计时器,System.Threading.Timer 将在时间过去时将回调排队在线程池线程上执行,并且不需要等待句柄,等待单个对象将在线程调用回调之前,绑定一个线程池线程,等待事件发出信号或超时到期。
@miniscalope No don't use ThreadPool.RegisterWaitForSingleObject instead of timer, System.Threading.Timer will queue a callback to be executed on a thread pool thread when the time has elapsed and doesn't require a wait handle, wait for single object will tie up a threadpool thread waiting for the event to be signalled or the timeout to expire before the thread calls the callback.
我对 System.Timer 的唯一不满是,大多数时候我发现它在轮询服务中使用了很长的延迟(小时、分钟),并且开发人员经常忘记在他们之前启动该事件启动计时器。 这意味着如果我启动应用程序或服务,我必须等到计时器过去(小时,分钟)才能真正执行。
当然,这不是计时器的问题,但我认为它经常被不当使用,因为它太容易被误用。
The only beef that I have with the System.Timer is that most of the time I have seen it used for long delays (hours, minutes) in polling services and developers often forget to launch the event Before they start the timer. This means that if I start the app or service, I have to wait until the timer elapses (hours, minutes) before it actually executes.
Sure, this is not a problem with the timer, but I think that its often used improperly by because its just too easy to misuse.
我记得实施了一种与埃里克类似的解决方案。
然而,这是一个有效的方法;)
I remember implementing a solution similar to Eric's one.
This is however a working one ;)
我认为如果您确实想将应用程序暂停指定的时间,Thread.Sleep 就可以了。 我认为人们之所以说这是一个糟糕的设计,是因为在大多数情况下,人们实际上并不希望应用程序暂停。
例如,我正在开发一个 pop3 客户端,其中程序员使用 Thread.Sleep(1000) 来等待套接字检索邮件。 在这种情况下,最好将事件处理程序连接到套接字,并在套接字完成后继续执行程序。
I think Thread.Sleep is fine if you really want to pause the application for a specified amount of time. I think the reason people say it is a bad design is because in most situations people don't actually want the application to pause.
For example, I was working on a pop3 client where the programmer was using Thread.Sleep(1000) to wait while the socket retrieved mail. In that situation it was better to hook up an event handler to the socket and continuing program execution after the socket had completed.
使用
线程池。 RegisterWaitForSingleObject
而不是计时器:use
ThreadPool.RegisterWaitForSingleObject
instead of timer: