睡觉(10)什么都不做?

时间:2011-12-09 00:11:52

标签: .net multithreading web-services remote-desktop

我的网络服务有一种奇怪的情况。

这是一个简单的 - 它创建一个不断运行的Thread,在后台执行一些磁盘检查,对于它执行的每个File.Exists,它进入Sleep(10),因此它不会消耗所有CPU核心。

一切正常,直到我从RDP登录。当我这样做时,这个线程会飙升并消耗尽可能多的东西。

在这里,看看......

我有两个核心,我的前台应用程序使用大约18%的CPU(在NOW-meter上显示了whis)。左侧是没有人登录时的CPU使用情况。

发生了什么事?还有更多 - 在这种情况下如何适当地限制线程?

enter image description here

产生问题的代码段:

foreach (string fi in files)
{
    if (_shouldStop)
    {
        break;
    }
    lock (_workItems)
    {
        StatusString = string.Format("Examining file Dir={0}\nmask={1}\nfile={2}\nqueue={3}",
            root, mask, fi, _workItems.Count);
    }
    lock (_workItems)
    {
        if (!_workItems.Contains(fi))
        {
            if (!File.Exists(TargetForFile(fi + ".hash")))
            {
                StatusString = string.Format("Adding file Dir={0}\nmask={1}\nfile={2}\nqueue={3}",
                root, mask, fi, _workItems.Count);
                _workItems.Add(fi);
            }
        }
    }
    Thread.Sleep(10);
}

小更新:

当代码作为Windows服务运行并且没有人连接到计算机时,即使Sleep(1000)也没有。我正式宣布它为WTF。

4 个答案:

答案 0 :(得分:5)

不要睡觉。将线程优先级设置为IDLE。

接下来要识别每个进程的CPU消耗 ,这样就不会追逐红鲱鱼了。打开Perfmom.exe并查看Process(*)\(*)对象(所有实例)。然后,您可以检查每个流程的% Processor Time% User Time ,并确定在RDP关闭时谁使用18%。

作为旁注,而不是shuffling same directories over and over again,为什么不使用change notifications mechanism

答案 1 :(得分:3)

睡眠10只有10毫秒 - 所以你真的很接近屈服并重新开始工作。

我的猜测是,当你登录时,有足够的进展,你的线程不会立即重新安排,所以它真的最终失效超过10毫秒(我想我读到了睡眠的最大分辨率是100毫克,顺便说一句。但是,当您不是RDP时,线程可以更频繁地重新安排,因此它会消耗更多的CPU。

要进行测试,请尝试将睡眠持续时间增加到500(0.5秒)或1000左右,以便为您提供明显的睡眠时间。

另一个测试,就是在do-nothing循环中抛出另一个线程,看看当你强制CPU忙时你的file.exists线程是否会有所收获。

答案 2 :(得分:2)

当我登录RDP时,

会出现类似的峰值,而我没有运行您的代码。 Occam的剃须刀会暗示它正在利用核心的RDP。

此外,如果你正在进行File.Exists,那么线程将在磁盘I / O上阻塞,如果有一点它会给CPU造成严重负担,那么它就不会在它完成时这一点。

最后,如果你还没有做过像Normal这样的流程优先级的事情,那么无论如何它都会与其他进程共享核心。如果它陷入紧密循环可能有点不好,但即使这样,调度程序也应该防止它自己造成太大的伤害。更新版本的Windows,如果你有多个核心,那就更是如此。

编辑:实际上,抓住这一切。为什么要自己轮询,而不是响应FileSystemWatcher事件。设置一个或多个FileSystemWatcher以观察感兴趣的目录,然后轮询特定文件存在的更改以响应该关注。代码工作量减少,而且应该更具响应性。

答案 3 :(得分:0)

感谢您提供的所有答案,但我会尝试提供我自己的答案。

此时我不需要更改体系结构,任何尝试使用任何数量的Sleep()都失败了。我搜索了除了SO之外的其他一些网站,并找到了一个线程,其中Jon Skeet建议使用Monitor来发出信号。

这激发了我尝试将Sleep更改为WaitOne的{​​{1}},我只会将其作为睡眠的替代方案,因为它似乎无法在我的情况。

尝试过,它有效!