我的网络服务有一种奇怪的情况。
这是一个简单的 - 它创建一个不断运行的Thread,在后台执行一些磁盘检查,对于它执行的每个File.Exists,它进入Sleep(10),因此它不会消耗所有CPU核心。
一切正常,直到我从RDP登录。当我这样做时,这个线程会飙升并消耗尽可能多的东西。
在这里,看看......
我有两个核心,我的前台应用程序使用大约18%的CPU(在NOW-meter上显示了whis)。左侧是没有人登录时的CPU使用情况。
发生了什么事?还有更多 - 在这种情况下如何适当地限制线程?
产生问题的代码段:
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。
答案 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)
会出现类似的峰值,而我没有运行您的代码。 Occam的剃须刀会暗示它正在利用核心的RDP。
此外,如果你正在进行File.Exists,那么线程将在磁盘I / O上阻塞,如果有一点它会给CPU造成严重负担,那么它就不会在它完成时这一点。
最后,如果你还没有做过像Normal这样的流程优先级的事情,那么无论如何它都会与其他进程共享核心。如果它陷入紧密循环可能有点不好,但即使这样,调度程序也应该防止它自己造成太大的伤害。更新版本的Windows,如果你有多个核心,那就更是如此。
编辑:实际上,抓住这一切。为什么要自己轮询,而不是响应FileSystemWatcher事件。设置一个或多个FileSystemWatcher
以观察感兴趣的目录,然后轮询特定文件存在的更改以响应该关注。代码工作量减少,而且应该更具响应性。
答案 3 :(得分:0)
感谢您提供的所有答案,但我会尝试提供我自己的答案。
此时我不需要更改体系结构,任何尝试使用任何数量的Sleep()
都失败了。我搜索了除了SO之外的其他一些网站,并找到了一个线程,其中Jon Skeet建议使用Monitor
来发出信号。
这激发了我尝试将Sleep
更改为WaitOne
的{{1}},我只会将其作为睡眠的替代方案,因为它似乎无法在我的情况。
尝试过,它有效!