Cyclone
Cyclone

Reputation: 18295

How to limit CPU usage in a while loop

How do you limit the CPU of a while loop?

In this case, the code which is inside the while loop:

Private Sub wait(ByVal time)
        Dim sw As New Stopwatch
        sw.Start()
        Do While sw.ElapsedMilliseconds < time And StillOpen = True
            Application.DoEvents()
        Loop
        sw.Stop()
    End Sub

But now, here is the issue. This loop is allowing the while loop to run every second, once a second, and the wait sub is causing this delay, as it should.

How can I limit the CPU that this is taking up? For some reason, my task manager says it is taking 50 CPUs to run this simple task, yet it should probably take no more than 1 or 2. Though the manager says it is taking that much CPU, my computer speed is not being affected at all, which is odd considering it is a two-year-old laptop.

I don't want any users to freak out about it, but knowing how people are these days....

Anyway, the language is vb.net. Can someone please help me?

Thanks!

EDIT: To clarify, that code is not inside the while loop itself, but a call for the subroutine is, i.e. wait(1000)

Upvotes: 2

Views: 14186

Answers (7)

Jer WasHere
Jer WasHere

Reputation: 33

You should take note of if you are doing this in the main UI Thread or a thread you have spun off.

For Threads the easiest way is to just Thread.Sleep(x miliseconds)

On the main UI thread I tend to use a DoEvents function in vb.net and vb6 like this

Public Sub TimeKiller(byval secondstowait as integer)
     dim tmptime as datetime = datetime.now

     do while datetime.now < dateadd("s",secondstowait,tmptime)
          Application.Doevents
     end while
End Sub

On the question of CPU usage I look at it like this.... if you make just a hard loop that like

while true
end while

I would expect to see very high cpu usage over 50% because the UI thread is hard blocking on this.... in most cases the windows system will limit the cpu usage of any given program so that its threads dont block the entire system.

The DoEvents ensure that windows message pumps fire correct and respond to correct. It also ensures that the garbage collector fires on time.

Also if you have other threads spun up off of your UI.Thread your UI.Thread can respond to events fired from these other threads....

In such cases where your calling form controls from other threads and do form.InvokeRequired routines will be able to respond correctly.

Also The only time you should be hard looping on the MainUI thread is when it is in response to some user activity and you need to put waits in for the user to see progress of something....

If it is some kind of automated process that is always running... look to moving it to another thread.

Or if its something that runs periodically on a timer or a time that kicks off a thread.

Somebody please tell me if I am wrong on these assumptions....

Not sure about the Using wh As New ManualResetEvent(False) wh.WaitOne(ms) as I have never heard of that and have no idea what that does.

Upvotes: 0

Mark
Mark

Reputation: 11

This is perfect as a VB.net sleep replacement. Now my console app is NOT reported as non responsive since I have no sleep commands!

Just add Imports System.Threading above your module and place this just above your sub main

Public Sub Wait(ByVal ms As Integer)

   Using wh As New ManualResetEvent(False)
        wh.WaitOne(ms)

    End Using
End Sub

Then, in your sub main, use

wait(100) 

to pause your app for 100 miliseconds.

Have fun

Upvotes: 0

user113476
user113476

Reputation:

If you don't mind blocking the current thread, you could use a WaitHandle.


    Public Sub Wait(ByVal ms As Integer)

        Using wh As New ManualResetEvent(False)
            wh.WaitOne(ms)
        End Using

    End Sub

    Sub Main()

        Console.WriteLine("Hello World!")
        Wait(5000)
        Console.WriteLine("Good-Bye!")

    End Sub

Of course, something more complex can be constructed depending on what you are trying to accomplish.

Upvotes: 0

Michael Petrotta
Michael Petrotta

Reputation: 60942

Your code is executing Application.DoEvents() constantly in the while loop, for the time duration specified in your time parameter. This will consume one core of your CPU, which is why you're seeing 50% processor usage (you have a dual-core processor, correct?). This is an ugly way to wait. You could instead call Thread.Sleep(), passing it the number of milliseconds you'd like your thread to wait.

If you'd like your application to stay responsive, you might also spin off a timer, and block the UI from any action until the timer triggers. Something like (lightly tested):

// constructor or designer code
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Tick += new EventHandler(timer_Tick);

void Wait(int interval)
{
    timer.Interval = interval;
    timer.Start();
    BlockUIOperations(); // implement yourself
}

void timer_Tick(object sender, EventArgs e)
{
    timer.Stop();   
    EnableUIOperations(); // implement yourself
}

Here's my attempt at a translation into VB:

'' Add a Timer object to the form named "Timer".
'' Hook its Tick event to Timer_Tick

Private Sub Wait(ByVal interval As Integer)
    Timer.Interval = interval
    Timer.Start()
    BlockUIOperations() '' implement yourself
End Sub

Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer.Tick
    Timer.Stop()
    EnableUIOperations() '' implement yourself
End Sub

Upvotes: 4

Faxwell Mingleton
Faxwell Mingleton

Reputation: 371

You could always perform some kind of sleep between iterations of the loop...

I'm not familiar with VB.NET but a duration of 100-200ms will probably be more than enough to drop the CPU usage.

Eg:

Do while (...)
    Application.blah();
    System.Threading.Thread.Sleep(150);
End

Edit After some research, I think the function you want is: System.Threading.Thread.Sleep()

Upvotes: 6

Guffa
Guffa

Reputation: 700562

Well, the CPU is always running at 100% when it's running, so the only practical way to limit the CPU usage is to run bursts or loop and sleeping in between.

Laptop CPUs usually have some SpeedStep technology or equievalent that will slow down the CPU when it's not working hard, but it's not reasonable to assume that your application would have access to control that, at least not directly. You might be able to affect it indirectly by measuring the CPU usage and adjust the length of the work and sleep cycles to get the desired result.

Upvotes: 0

iDevlop
iDevlop

Reputation: 25272

Use a timer event !!! Nearly no cpu effort.

Upvotes: 7

Related Questions