0

I need to do some background work every 20 seconds (it doesn't have to be exactly 20000ms, I can allow delays). I am using a Backgroundworker that executes the function and then wait another 20 seconds using a Timer:

private readonly BackgroundWorker Worker = new BackgroundWorker();
volatile bool keepWorkerRunning;

Worker.DoWork += Worker_DoWork;


    private void Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        System.Timers.Timer aTimer = new System.Timers.Timer();
        aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
        aTimer.Interval = 20000;
        aTimer.Enabled = true;
        keepWorkerRunning = true;
        while (keepWorkerRunning) ;
        aTimer.Enabled = false;
    }

This worker is active for the whole time while the software is running.

The problem is that it takes most of the CPU. I noticed that my software is using around 70% of the CPU all the time, and just deactivating the Backgroundworker the CPU usage drops to 0.5%.

How can I do the same job without overloading the CPU?

Hamma
  • 183
  • 1
  • 4
  • 12
  • 1
    Why do you use a timer and a BackgroundWorker at the same time? You could just do the stuff you want to do in the `Tick` handler of a single timer, which ticks every 20s. Also, the reason for the CPU usage is probably not the BackgroundWorker/Timer construction, but your busy loop (`while(true)`) – LInsoDeTeh Jul 22 '15 at 10:56
  • I remember copying this structure from some previous post or answer. It does exactly the job I need, but it takes too much CPU power. Do you have an alternative solution that would take less? Note that it has to be done on a different thread than the UI. – Hamma Jul 22 '15 at 10:58
  • If you really want to go with that solution, replace `while(keepWorkerRunning);` with something like `while(keepWorkerRunning) { Threading.Thread.Sleep(100); }` to get rid of the busy loop in which you occupy the full CPU power. – LInsoDeTeh Jul 22 '15 at 11:02
  • Throw away the BackgroundWorker and do the background work in the Elapsed handler of the Timer, which runs on a ThreadPool thread. See [this question](http://stackoverflow.com/q/1416803/1136211) about the differences between Times.Timer and Threading.Timer. – Clemens Jul 22 '15 at 11:03
  • 1
    @LInsoDeTeh, `Thread.Sleep(100)` is a very poor solution for those king of things. Please don't do that and don't suggest others to do that. – dymanoid Jul 22 '15 at 11:05
  • @damanoid: I know, I wouldn't have used the whole Worker/Timer construction at all, as I pointed out already. But as far as I understood, OP wanted to keep this construction. – LInsoDeTeh Jul 22 '15 at 11:07
  • @LInsoDeTeh: Well, is there is an easy fix of course it would be handier to keep the construction; but I am in the process of reviewing the code so if there is a better way to make it more efficient I will change the structure. – Hamma Jul 22 '15 at 11:09
  • @Hamma. Change the structure! Do what was proposed in the answer. You don't have to be familiar with the thread pool. The Elapsed handler is already called on a ThreadPool thread. You don't have to do anything for that. Just put all your background code in the Elapsed handler, that's it. Doing something every 20 seconds is exactly what timers were made for. – Clemens Jul 22 '15 at 11:11
  • Will this solution prevent me to call Invoke from the code if necessary? – Hamma Jul 22 '15 at 11:13
  • No, it won't. You may however use a DispatcherTimer, which has a Tick handler that runs in the UI thread. Then you won't have to use Invoke or BeginInvoke to update your UI. Note however that the Tick handler must not execute a lengthy operation, because then it would block the UI thread. – Clemens Jul 22 '15 at 11:37
  • No, I need the operations to be handled outside UI. I might need to access the UI thread sometimes, but in general I need to work in the background. – Hamma Jul 22 '15 at 11:39
  • Then System.Timers.Timer or System.Threading.Timer is the correct approach. – Clemens Jul 22 '15 at 11:44

1 Answers1

2

The CPU is eaten by this loop:

while (keepWorkerRunning);

You effectively instruct the CPU to loop "doing nothing" as fast as possible. Hence 70% CPU load, it might be even worse (up to 100% depending on your CPU/cores).

Don't use BackgroundWorker at all. The Elapsed event is raised by the Timer on a thread pool thread (the SynchronizingObject property of the timer should be null), so it will run in background.

More information you can get here.


Update: As requested, here is a sample.

using System.Timers;

class MyClass : IDisposable
{
  readonly Timer aTimer = new Timer(20000);

  public void StartTimer()
  {
    this.aTimer.Elapsed += this.OnTimedEvent;
    this.aTimer.Enabled = true;
  }

  void OnTimedEvent(object source, ElapsedEventArgs e)
  {
    // do your background work here
  }
}
dymanoid
  • 14,771
  • 4
  • 36
  • 64
  • Ok I will look it up for that as I am not familiar with the thread pool. Just for information, using something like Thread.Sleep(20000) in the Backgroundthread would consume as much CPU as now? – Hamma Jul 22 '15 at 11:08
  • @Hamma, you don't need to put `Thread.Sleep()` in the event handler, since the `Timer` object manages to call your handler every 20 seconds. – dymanoid Jul 22 '15 at 11:20
  • Do you have a quick structure that I can follow to implement the Timer? – Hamma Jul 22 '15 at 11:40
  • @Hamma You already have the Elapsed handler (`OnTimedEvent`). Put all your background code there. That's all. – Clemens Jul 22 '15 at 11:47
  • Can I ask why is this a better solution then `System.Threading.Timer`? – Hamma Jul 22 '15 at 12:03
  • I know there is a question linked about that, but its answer is another link and I cannot see it. – Hamma Jul 22 '15 at 12:09
  • @Hamma, for a good overview, you can look [here](http://www.codeproject.com/Articles/167365/All-about-NET-Timers-A-Comparison). – dymanoid Jul 22 '15 at 12:16