【问题标题】:System.Timers.Timer Elapsed taking 10 times longer to execute than a Button_clickSystem.Timers.Timer Elapsed 的执行时间比 Button_click 长 10 倍
【发布时间】:2009-09-24 09:58:43
【问题描述】:

我有一个相当密集的方法,它接受给定的集合,复制项目(Item 类有正确定义的 Copy() 方法),用数据填充项目并将填充的集合返回到类的集合属性

//populate Collection containing 40 items
MyClass.CollectionOfItems = GetPopulatedCollection(MyClass.CollectionOfItems );

此方法以两种方式调用:根据请求和通过 System.Timers.Timer 对象的“Elapsed”事件。

现在集合中的 40 件物品几乎不需要任何时间。无论是通过 button_click 填充“ad hoc”还是通过 Timer 对象填充。

现在,当我增加集合的大小(另一个具有 1000 个项目的 MyClass 对象)时,可以预见该过程需要更长的时间,但总共大约需要 6 秒。 很好,那里没有问题。在初始化时调用 (form_load) 或临时调用 (button_click),它会停留在 6 秒左右。

//populate Collection containing 1000 items
MyClass.CollectionOfItems = GetPopulatedCollection(MyClass.CollectionOfItems );

但是,System.Timers.Timer 对象正在调用相同的方法(如在确切的代码行中)。而 Elapsed 大约需要 60 秒(其他运行 unclide 56 秒、1 分钟 2 秒、1 分钟 10 秒......你明白了)。 相同过程的十倍!

我知道 System.Timers.Timer 对象是在线程池中执行的。这可能是原因吗?是线程池的优先级较低还是整个排队都占用了时间?

简而言之,有什么更好的方法呢?使用 System.Windows.Forms.Timer 在同一个 UI 线程中执行?

谢谢!

好的,补充一些信息:

计时器操作发生在 UI 调用的 DLL 中。主“处理程序”类本身有一个定时器对象的集合,它们都订阅同一个事件处理程序。 处理程序类的初始化有点像这样:

UpdateIntervalTimer tmr = new UpdateIntervalTimer(indexPosition);
tmr.Interval = MyClass.UpdateInterval * 60000; //Time in minutes
tmr.Elapsed += new System.Timers.ElapsedEventHandler(tmr_Elapsed);
this.listIntervalTimers.Add(tmr);

实际上,我继承了 Timer 类以赋予它一个“索引”属性(还有 eventArgs)。这样,在一个事件处理程序 (tmr_Elapsed) 中,我可以识别计时器用于哪个 MyClass 对象并采取行动。

处理程序类已经在它自己的线程中运行,并触发一个自定义事件以深入了解其操作。 该事件在 UI 中处理(UI 控件的跨线程访问等),并在收到事件处理时显示。对于“初始化”和“临时”调用都是如此(在这些情况下没有问题)。

实际的 Elapsed 事件如下所示:

private void tmr_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
            UpdateIntervalTimer tmr;
            tmr = (UpdateIntervalTimer)sender;

            MyClass c = listOfClasses[tmr.IndexPosition];

            observerEventArguments = new MyHandlerEventArgs("Timer is updating data for " + MyClass.ID);
            MessagePosted(this, observerEventArguments);

            try
            {
                //preparation related code


                MyClass.CollectionOfItems = GetPopulatedCollection(MyClass.CollectionOfItems);


                observerEventArguments = new ProfileObserverEventArgs(MyClass.ID + ": Data successfully updated");
                MessagePosted(this, observerEventArguments);
            }
            catch (Exception exUpdateData)
            {
                observerEventArguments = new MyHandlerEventArgs("There was an error updating the data for '" + MyClass.ID + "': " + exUpdateData.Message);
                MessagePosted(this, observerEventArguments);
            }
        }

【问题讨论】:

  • 能否请您显示 Elapsed 事件处理程序的代码?
  • ...还有一个你如何测量时间的样本,也许?
  • 好的,所以我尝试过使用 System.Windows.Forms.Timer,不同之处就在于它。回到 6 秒。奇怪的是,我的 CPU(四核 2.4)在 System.Timers.Timer 对象正在运行但对 Windows.Forms.Timer 几乎没有闪烁时进行了艰苦的战斗(40%)。我现在可以继续使用 Forms.Timer 对象。有没有人对为什么 CPU 会与线程池中的某些东西如此激烈地斗争有更多的想法(我的意思是,池的想法不是让事情变得更快吗?)

标签: c# multithreading timer threadpool


【解决方案1】:

嗯,UI 线程可能具有更高的优先级 - 毕竟,它是为了保持 UI 响应。但是,还有其他可能发生的事情。您的方法是否以线程安全的方式访问 UI?如果是这样,显然它不需要在线程之间编组时会更快。

您可以尝试提高线程池线程的优先级,看看这是否会提高性能 - 但除此之外,我们还需要更多信息。

不会建议您在 UI 线程上执行此操作 - 将 UI 挂起 6 秒并不能带来良好的用户体验 :(

【讨论】:

  • 好的,这值得进一步调查,但现在可以使用 System.Windows.Forms.Timer。我将不得不尝试优化流程本身或调整优先级。
【解决方案2】:

当您仍在计时器中工作时,间隔是否已经过去,导致它多次执行相同的工作?这是我认为 UI 计时器比 system.timers.timer/system.threading.timer 工作得更快的唯一原因,因为 UI 计时器是单线程的,在完成之前不能再次过去,而其他计时器可以。

【讨论】:

  • 我理解你的论点,但计时器设置为 15 分钟。我有一个线程安全的列表框,可以输出代码中发生的事情;完成的工作肯定在下一个 Tick(或 Elapsed)事件中。我可能不得不查看多线程解决方案而不是线程池解决方案。
猜你喜欢
  • 1970-01-01
  • 2015-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-06
  • 1970-01-01
  • 2020-04-27
  • 2018-01-19
相关资源
最近更新 更多