.net 中线程中的计时器
我想要一个新线程内的计时器滴答/已过去事件。看来我不能使用 Windows 计时器。但如果我使用 Timers.Timer,它会从线程池中为每个经过的事件创建工作线程。有没有办法让这些事件发生在同一个线程中?
更新:
感谢大家回答这个问题。
不过,我整件事背后的意图听起来可能有点疯狂。我要你纠正我。这是我(作为新手)在尝试实现这一目标时的想法。我正在尝试每 2 秒执行一项任务。当我使用 Timers.Timer 时,它每 2 秒创建一个线程,我认为这是一种开销。
我的主线程和其他线程需要大量处理器时间来执行其任务。因此,如果我可以避免创建这些线程,那么每次计时器到期时,我都会节省处理器的微秒时间来为我的主线程和其他线程创建线程。
我进行了快速测试并比较了几种解决方案。每种情况下的间隔为 1000 毫秒。 100 个刻度。
解决方案1:等待/睡眠的无限循环{00:01:42.0068344}
解决方案2:使用Brian的同步器{00:01:42.4068573}
解决方案3:Timers.Timer,因为它是{00:01:42.4018571}
这应该告诉我2.0068344,2.4068573 , 2.4018571 是除了 100 个刻度的 1000 毫秒时间间隔之外,在后台执行其他操作所浪费的时间。这应该意味着当解决方案1满足您的需求时,它是性能方面最好的解决方案?
这也应该意味着,尽管 Brian 的解决方案与一个线程同步,但它实际上是在后台创建线程。
请确认或纠正我。
I want a timer tick/elapsed event inside a new thread. It seems like I cannot use the Windows timer. But if I use the Timers.Timer, it creates worked thread from the threadpool for each elapsed event. Is there a way to make these events to occur in the same thread?
Update:
Thank you everybody for answering this question.
My intention behind the whole thing might sound a little crazy though. I want you to correct me. This is my thinking(as a novice) when I am trying to acieve this. I am trying perform a task every 2 seconds. When I use Timers.Timer, it creates a thread every 2 seconds which I am thinking it as an overhead.
My main thread and my other threads need a lot of processor's time to perform their tasks. So, if I can avoid creating these Threads, I am saving whatever microseconds of the processor to create a thread each time timer elapsed, for my main and other threads.
I made a quick tests and compared few solutions. 1000 msec interval in each case. 100 ticks.
Solution1: infinite loop with waits/sleep {00:01:42.0068344}
solution2: Using Brian's Synchronizer {00:01:42.4068573}
solution3: Timers.Timer as it is {00:01:42.4018571}
This should tell me that 2.0068344, 2.4068573, 2.4018571 are the times wasted for other things in the background other than the time interval of 1000 msec for 100 ticks. This should mean when solution1 meet your needs, it is the best solution performance-wise??
This should also mean that though Brian's solution is synchronized to one thread, it is in-fact creating threads in the background.
Please confirm it or correct me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
是的。您可以让
System.Timers.Timer
在同一线程中执行Elapsed
事件处理程序。为此,您需要将SynchronizingObject
属性设置为一个对象,该对象会将执行编组到您选择的线程上。但是,重要的是要认识到您不能将执行注入到随机线程上。接收线程必须经过专门设计,以允许编组方法调用的执行。这是
Synchronizer
类的代码。此代码使用 .NET BCL 4.0 中的 BlockingCollection 类。如果您没有使用 4.0,则可以将其替换为 Stephen Toub 的 阻塞队列。更新:
您需要了解
System.Timers.Timer
的工作原理。它实际上在幕后使用 System.Threading.Timer 并在 ThreadPool 线程上执行事件处理程序。所以它根本没有真正创建任何线程。线程池中的相同线程会被一遍又一遍地回收。没有线程创建开销。这就是线程池的全部意义。现在,我在这里提供的解决方案仍然在幕后使用 ThreadPool,但不是让工作项直接执行 Elapsed 事件处理程序,而是执行 Synchronizer .BeginInvoke 方法将事件处理程序编组到
Synchronizer
创建的线程上。因此,我在这里提供的解决方案速度较慢也就不足为奇了。就我个人而言,我会坚持使用解决方案#1,因为它更容易。此时我不会太担心性能。
Yes. You can make the
System.Timers.Timer
execute theElapsed
event handler in the same thread. To do this you need to set theSynchronizingObject
property to an object that will marshal the execution onto a thread of your choosing. However, it is important to realize that you cannot just inject execution onto a random thread. The receiving thread has to be specifically designed to allow marshaling the execution of method calls.And here is the code for the
Synchronizer
class. This code uses the BlockingCollection class from 4.0 of the .NET BCL. If you are not using 4.0 then you can replace it with Stephen Toub's BlockingQueue.Update:
You need to understand how
System.Timers.Timer
works. It actually usesSystem.Threading.Timer
behind the scenes and executes the event handler on aThreadPool
thread. So it is not really creating any threads at all. The same ones from the thread pool are getting recycled over and over again. There is no thread creation overhead. That is the whole point of a thread pool.Now, the solution I provided here still uses the
ThreadPool
behind the scenes, but instead of having the work item execute theElapsed
event handler directly it is executing theSynchronizer.BeginInvoke
method which marshals the event handler onto the thread that theSynchronizer
created.So it should be no surpise that the solution I provided here would be slower. Personally, I would stick to solution #1 as it is easier. I would not worry a whole lot about performance at this point.
不,这也没有多大意义。
事件不能只是“闯入”线程,线程必须配合。
您可以做的是创建一个重复循环并等待信号量的线程。然后使用任何类型的计时器来触发该信号量。
No, and that would not make much sense either.
An event cannot just 'break in' to a thread, the thread has to cooperate.
What you can do is to create a Thread that loops repeatedly and waits on a semaphore. Then use any kind of Timer to trigger that semaphore.
我认为提供另一个答案会有好处。原因是因为我的另一个答案让事情变得太复杂了。如果您只想确保在同一个实例上定期执行任务,则确实没有必要在 System.Timers.Timer 实例上设置 SynchronzingObject 属性。线。启动一个在无限循环中旋转的新线程来执行您最初放置在
Elapsed
事件中的内容要容易得多。I thought it would beneficial to provide another answer. The reason is because my other answer complicates things too much. It is really unnecessary to set the
SynchronzingObject
property on aSystem.Timers.Timer
instance if all you are wanting to do is make sure that a task is executed periodically on the same thread. It is much easier to start a new thread that spins around in an infinite loop executing what you would have originally placed in theElapsed
event.如果您希望在特定线程上执行定时事件,您至少有几个选择:
If you want a timed event to execute on a particular thread, you have at least a couple options:
我建议您创建一个线程来监视由计时器的已用事件处理程序提供的阻塞队列。那么事件处理程序使用哪个线程并不重要,并且由于它所做的只是将某些内容放入队列中,因此该线程的持续时间将很短。
有关良好的阻塞队列实现,请参阅 Marc Gravell 的回答:创建阻塞队列在.NET 中? 。
I recommend that you create a thread that watches a blocking queue that is fed by your timer's elapsed event handler. Then it won't matter which thread the event handler uses, and since all it does is drop something into the queue, that thread's duration will be brief.
For a good blocking queue implementation, see Marc Gravell's answer: Creating a blocking Queue<T> in .NET?.