在将来的某个时间调用单个操作的最佳方式?
我想触发一个计时器在将来的某个时刻执行一次。为了代码简洁,我想使用 lambda 表达式。所以我想做一些类似的事情......
(new System.Threading.Timer(() => { DoSomething(); },
null, // no state required
TimeSpan.FromSeconds(x), // Do it in x seconds
TimeSpan.FromMilliseconds(-1)); // don't repeat
我认为它非常整洁。但在这种情况下,Timer 对象没有被释放。解决这个问题的最佳方法是什么?或者,我应该在这里采取完全不同的方法吗?
I want to fire off a timer to execute once at some point in the future. I want to use a lambda expression for code brevity. So I want to do something like...
(new System.Threading.Timer(() => { DoSomething(); },
null, // no state required
TimeSpan.FromSeconds(x), // Do it in x seconds
TimeSpan.FromMilliseconds(-1)); // don't repeat
I think it's pretty tidy. But in this case, the Timer object is not disposed. What is the best way to fix this? Or, should I be doing a totally different approach here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
这种方法是有缺陷的。
您正在内存中创建一个没有引用的对象。这意味着计时器对象可被垃圾收集。虽然此代码有时会起作用,但您无法预测垃圾收集何时启动并删除计时器。
例如,在下面的代码中,我强制进行垃圾收集,这会导致计时器永远不会触发。
That approach is flawed.
You are creating an object in memory with no reference to it. This means that the timer object is available to be garbage collected. While this code will work some of the time, you cannot predict when a garbage collection will kick in and remove the timer.
For example in the code below I force a garbage collection and it causes the timer to never fire.
这将实现你想要的,但我不确定它是最好的解决方案。我认为它简短而优雅,但可能比它的价值更令人困惑和难以理解。
This will accomplish what you want, but I am not sure its the best solution. I think its something that short and elegant, but might be more confusing and difficult to follow than its worth.
不使用计时器,而是利用线程池:
这可以在垃圾回收中幸存下来,因为您不必保留对任何内容的引用。
Instead of using a timer, leverage the thread pool instead:
This survives garbage collection since you don't have to retain a reference to anything.
你可以只包装计时器类......
You could just wrap the timer class...
计时器对象可能实现了析构函数。
您可以在文档或反射器中轻松验证这一点。
如果这是真的,你就不用担心。除非这段代码被多次调用,在这种情况下,您应该努力确定计时器的释放,这意味着您将保存一个计时器数组。
The timer object probably implements a destructor.
You can easily verify this in documentation or in the reflector.
If this is true, you shouldn't worry about it. Unless this piece of code gets called many times, in which case you should strive for deterministic deallocation of timers, meaning you would hold an array of timers, for example.
如果您有一个 Dispatcher 并且希望处于 UI (Dispatcher) 线程中,请使用此函数:
此函数不是异步的,因为您不想在函数内等待。如果您想在不同时间安排多个事件,则这种方法可能很有用,但也许您确实需要以下方法:
它执行相同的操作,但要求在函数末尾发生等待。
由于您可能没有调度程序或想要使用它,但仍然想在不同时间安排多个操作,所以我会使用线程:
如果您想避免异步,我建议不要使用线程池并替换等待
Task.Delay(delayMs)
调用与Thread.Sleep(delayMs)
调用If you have a Dispatcher and want to be in the UI (Dispatcher) thread, use this:
This function is not async because you did not want to wait within your function. This approach might be useful if you wanted to schedule more than one events at different times, but perhaps you really want the approach below:
Which does the same thing, but requires the await to happen at the end of your function.
Since you may not have a Dispatcher or want to use it, but still want to schedule multiple operations at different times, I would use a thread:
If you want to avoid async, I would recommend not using the threadpool and replacing the await
Task.Delay(delayMs)
call with aThread.Sleep(delayMs)
call您可以使用
TaskCompletionSource
例如:并像这样调用它:
Or simply call:
You could use
TaskCompletionSource
for example:and call it like:
Or simply call: