Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Thread.Sleep() is so CPU intensive?

I have an ASP.NET page with this pseduo code:

while (read)
{
   Response.OutputStream.Write(buffer, 0, buffer.Length);
   Response.Flush();
}

Any client who requests this page will start to download a binary file. Everything is OK at this point but clients had no limit in download speed so changed the above code to this:

while (read)
{
   Response.OutputStream.Write(buffer, 0, buffer.Length);
   Response.Flush();
   Thread.Sleep(500);
}

Speed problem is solved now, but under test with 100 concurrent clients who connect one after another (3 seconds lag between each new connection) the CPU usage increases when the number of clients increases and when there are 70 ~ 80 concurrent clients CPU reaches 100% and any new connection is refused. Numbers may be different on other machines but the question is why Thread.Sleep() is so CPU intensive and is there any way to speed done the client without CPU rising ?

I can do it at IIS level but I need more control from inside of my application.

like image 522
Xaqron Avatar asked Oct 07 '10 21:10

Xaqron


1 Answers

Let's take a look at whether Michael's answer seems reasonable.

Now, Michael wisely points out that Thread.Sleep(500) shouldn't cost much in the way of CPU. That's all well and good in theory, but let's see if that pans out in practice.

    static void Main(string[] args) {
        for(int i = 0; i != 10000; ++i)
        {
            Thread.Sleep(500);
        }
    }

Running this, the CPU use of the application hovers around the 0% mark.

Michael also points out that since all the threads that ASP.NET has to use are sleeping, it will have to spawn new threads, and offers that this is expensive. Let's try not sleeping, but doing lots of spawning:

    static void Main(string[] args) {
        for(int i = 0; i != 10000; ++i)
        {
            new Thread(o => {}).Start();
        }
    }

We create lots of threads, but they just execute a null operation. That uses a lot of CPU, even though the threads aren't doing anything.

The total number of threads never gets very high though, because each lives for such a short time. Lets combine the two:

    static void Main(string[] args) {
        for(int i = 0; i != 10000; ++i)
        {
            new Thread(o => {Thread.Sleep(500);}).Start();
        }
    }

Adding this operation that we have shown to be low in CPU use to each thread increases CPU use even more, as the threads mount up. If I run it in a debugger it pushes up to near 100% CPU. If I run it outside of a debugger, it performs a bit better, but only because it throws an out of memory exception before it gets a chance to hit 100%.

So, it isn't Thread.Sleep itself that is the problem, but the side-effect that having all available threads sleep forces more and more threads to be created to handle other work, just as Michael said.

like image 82
Jon Hanna Avatar answered Oct 14 '22 11:10

Jon Hanna