Question

I have a bug I can't really figure out. System is 10.5 (32 bits) with Haskell Platform 2010, GHC 6.12

Consider the following:

loop :: IO ()
loop = do
    return ()
    loop

main = do
    loop

when compiled,

ghc --make test.hs

this code ends up taking 100% of the CPU's time. Why is that? How do you write a program in Haskell that loops like this while being nice to the laptop's battery?

Concurrent's "yield" does not seem to do anything interesting.

Was it helpful?

Solution

Same reason a tight loop in any language eats an entire CPU. You didn't tell it to loop any slower than "as fast as it can". Look at Control.Concurrent's threadDelay.

OTHER TIPS

An infinite loop with no breaks will cause 100% CPU usage in any language on any computer
If you must do a loop like this, use a delay or sleep or lower the thread's priority if it is eating up too many cycles.

A similar imperative (Python-like syntax) loop would be:

def loop():
    x = ()
    loop()

Or without recursion:

def loop():
   while True:
       x = ()

All this will do in any language is tell the CPU to keep executing instructions with no useful result, forever. Without specifically telling the program to do something other than keep executing these instructions (such as suspend for a while between loops), how could it do anything but use 100% CPU?

Control.Concurrent.yield allows any other thread in your program to "get a turn" at execution. If there are no other threads then it doesn't do anything. If all your other threads are executing such a loop, then it'll still use 100% CPU. If you have other threads that are sometimes IO bound rather than CPU bound, I do not know for certain, but I'm reasonably sure Haskell's runtime system switch back to something for the CPU to do (if possible) whenever threads are waiting for IO, so you'd probably see close to 100% CPU usage if you had this loop running and yielding, even if you have loads of other threads that won't use 100% CPU on their own.

If other unrelated programs are also running, then almost all modern desktop hardware and operating systems will try to share the CPU resources between them, regardless of whether you're using yield or not. Generally, this means that any time the other programs don't have work for the CPU your loop program will be run, plus it will also steal some of the CPU time that could have been used to execute other programs. This means that while this loop program is executing you would usually see close to 100% CPU usage regardless of what else is running, and using yield won't particularly make a difference to how much CPU time is available to other programs.

Control.Concurrent.threadDelay puts the thread to sleep for (at least) a given amount of time. If that leaves the CPU with nothing to execute, then you'll see your system running at less than 100% CPU.

Insert a delay into your loop, so that processor time would be given to some another process.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top