views:

831

answers:

2

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);
            }
        }
+1  A: 

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 :(

Jon Skeet
Ok, this warrants further investigation but using the System.Windows.Forms.Timer is ok for now. I'll have to try to optimize the process itself or play with the the priorities.
MoSlo
A: 

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.

I understand your argument, but the timer is set to 15 minutes. I've got a thread-safe listbox giving output as to what's happening inside the code; the work done is definitely inside of the next Tick (or Elapsed) event. I might have to look at a multi-treaded solution instead of a thread-pooled one.
MoSlo