System.Timers.Timer Elapsed 执行时间比 Button_click 长 10 倍

发布于 2024-08-05 21:22:58 字数 2629 浏览 10 评论 0原文

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

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

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

现在,收藏中的 40 件物品几乎不需要任何时间。无论是通过按钮单击“临时”填充还是由 Timer 对象填充。

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

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

但是,System.Timers.Timer 对象正在调用相同的方法(如在确切的代码行中)。而 Elapsed 大约需要 60 秒(其他运行需要 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 类并为其赋予了一个“index”属性(还有 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);
            }
        }

I have a fairly process intensive method that takes a given collection, copies the items(the Item class has its Copy() method properly defined), populates the item with data and returns the populated collection to the class's collection property

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

This method is called in two ways: upon request and via a System.Timers.Timer object's 'Elapsed' event.

Now 40 items in the collection take almost no time at all. Whether being populated 'ad hoc' by say a button_click or populated by the Timer object.

Now when I increase the size of the collection (another MyClass object that has 1000 items), the process predictably takes longer, but around 6sec in total.
That's fine, no problems there. Being called upon initialization (form_load) or being called ad hoc (button_click) it stays around 6sec.

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

But, the SAME METHOD (as in the exact line of code) is being called by the System.Timers.Timer object. And that Elapsed takes around 60 seconds (other runs unclide 56sec, 1min 2Sec, 1min 10 sec... you get the idea).
Ten times as long for the same process!

I know the System.Timers.Timer object is executed in the Thread-pool. Could this be the reason? Is the thread-pool given lower priority or is the whole queuing thing taking up the time?

In short, what would be a better approach to this? Using the System.Windows.Forms.Timer to execute in the same UI thread?

Thanks!

Ok, some additional info:

The timer operation is occurring within a DLL being called by the UI. The main 'handler' class itself has a collection of timer objects all subscribing to the same event handler.
The handler class' initialization works kinda like this:

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);

I've actually inherited the Timer class to give it an 'index' property (The eventArgs as well). That way within one event handler (tmr_Elapsed) i can identify which MyClass object the timer is for and take action.

The handler class is already running in a thread of its own and fires a custom event to give insight to its operations.
The event is handled in the UI (cross-threading access of UI controls and whatnot) and displayed with the time recievedthe event is handled. This is true for both 'initialization' and 'ad hoc' calls (there is no problem in those cases).

The actual Elapsed event looks as follows:

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);
            }
        }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

毁梦 2024-08-12 21:22:58

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

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

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

Well, the UI thread is likely to have a higher priority - after all, it's meant to keep the UI responsive. However, there are other things that could be going on. Does your method access the UI in a thread-safe manner? If so, obviously it's going to be faster when it doesn't need to marshall between threads.

You could try boosting the priority of the thread-pool thread to see if that improves performance - but apart from that, we'll need more info.

I wouldn't advise you to do this on the UI thread - hanging the UI for 6 seconds doesn't make for a nice user experience :(

尘世孤行 2024-08-12 21:22:58

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

Is the interval elapsing while you're still doing work in the timer, causing it to do the same work multiple times? That's the only reason I can think that the UI timer works faster than the system.timers.timer/system.threading.timer, since the UI timer is single threaded and cannot elapse again until it's finished, while the others can.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文