为什么Thread.Sleep()是如此CPU密集型?

Xaq*_*ron 11 c# asp.net performance multithreading

我有一个带有这个pseduo代码的ASP.NET页面:

while (read)
{
   Response.OutputStream.Write(buffer, 0, buffer.Length);
   Response.Flush();
}
Run Code Online (Sandbox Code Playgroud)

请求此页面的任何客户端都将开始下载二进制文件.此时一切正常,但客户端的下载速度没有限制,因此将上述代码更改为:

while (read)
{
   Response.OutputStream.Write(buffer, 0, buffer.Length);
   Response.Flush();
   Thread.Sleep(500);
}
Run Code Online (Sandbox Code Playgroud)

速度问题现在已经解决,但是在测试中有100个并发客户端一个接一个地连接(每个新连接之间延迟3秒),当客户端数量增加时CPU使用率增加,并且当70到80个并发客户端CPU达到100%时CPU使用率增加并且任何新连接都被拒绝.其他机器上的数字可能不同,但问题是为什么Thread.Sleep()是如此CPU密集型,有没有办法加速客户端没有CPU上升?

我可以在IIS级别执行此操作,但我需要从应用程序内部进行更多控制.

Jon*_*nna 41

让我们来看看迈克尔的答案是否合理.

现在,迈克尔明智地指出,Thread.Sleep(500)不应该在CPU的方式上花费太多.这在理论上一切都很好,但让我们看看这是否在实践中实现.

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

运行它,应用程序的CPU使用率徘徊在0%左右.

迈克尔还指出,由于ASP.NET必须使用的所有线程都处于休眠状态,因此必须生成新线程,并提供这样做很昂贵.让我们试着不要睡觉,但要做很多产卵:

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

我们创建了很多线程,但它们只执行一个null操作.这使用了大量的CPU,即使线程没有做任何事情.

但是线程的总数永远不会很高,因为每个线程都存在这么短的时间.让两者结合起来:

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

将这个我们已经证明CPU使用率低的操作添加到每个线程会增加CPU的使用量,因为线程会增加.如果我在调试器中运行它,它会推高到接近100%的CPU.如果我在调试器之外运行它,它会更好一点,但只是因为它在它有机会达到100%之前抛出一个内存不足的异常.

因此,问题不在于Thread.Sleep本身,但是让所有可用线程睡眠的副作用迫使越来越多的线程被创建来处理其他工作,就像迈克尔所说的那样.


Mic*_*urr 32

只是一个猜测:

我不认为这会Thread.Sleep()占用CPU - 这是因为你导致线程被绑定响应请求这么长时间,系统需要启动新线程(和其他资源)来响应因为线程池中不再提供这些休眠线程的新请求.

  • 但是你仍然在工作池中饱和.您不应该使用sleep而是async IO API. (4认同)
  • +1 启动新线程/非常/昂贵,并且很容易在 IIS 上出现线程匮乏的情况 (2认同)