Sleep(10) 什么也没做?
我的网络服务遇到了奇怪的情况。
这是一个简单的方法 - 它创建一个不断运行的线程,在后台执行一些磁盘检查,并且对于它执行的每个 File.Exists,它都会进入 Sleep(10),因此它不会消耗所有 CPU 核心。
一切正常,直到我从 RDP 登录为止。当我这样做时,该线程将峰值并消耗尽可能多的资源。
在这里,看看...
我有两个核心,我的前台应用程序使用了大约 18% 的 CPU(这显示在 NOW 仪表上)。左边是无人登录时的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);
}
小更新:
甚至 Sleep(1000)
当代码作为 Windows 服务运行并且没有人连接到机器时,什么也不做。我正式宣布这是WTF。
I have a strange situation with my web service.
It is a simple one - it creates a Thread that runs constantly, doing some disk checks in the background, and for every File.Exists that it performs, it goes into Sleep(10) so it doesn't consume ALL of the CPU core.
It all works well, until I log of from RDP. When I do that, this thread will spike and consume as much as it can.
Here, have a look-see...
I have two cores, and my foreground app is using about 18% CPU (whis is shown on the NOW-meter). To the left is the CPU usage when no-one is logged on.
What is going on? And more - what to do to throttle the Thread appropriately under this circumstance?
My code snippet that produces the issue:
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);
}
Small update:
Even Sleep(1000)
does NOTHING when code is run as windows service and no-one is connected to the machine. I officially declare it a WTF.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
当我登录 RDP 时出现这样的峰值,并且我没有运行您的代码。奥卡姆剃刀建议 RDP 正在利用核心。
此外,如果你正在执行 File.Exists,线程无论如何都会在磁盘 I/O 上阻塞,如果某个点它给 CPU 带来了严重的负担,那么当它刚刚完成时就不会了。
最后,如果您没有做任何疯狂的事情,例如从“正常”中提高进程优先级,那么无论如何它都会与其他进程共享核心。如果它陷入紧密循环,可能会有点糟糕,但即使如此,调度程序也应该防止它自己造成太大的伤害。对于较新版本的 Windows,并且您有多个内核,情况更是如此。
编辑:实际上,把所有这些都划掉。为什么要自己循环轮询而不是响应 FileSystemWatcher 事件。设置一个或多个 FileSystemWatcher 来监视感兴趣的目录,然后轮询您关心的特定文件存在更改以响应该更改。代码工作量减少,响应速度也应该更快。
get spikes like that when I log onto RDP, and I don't have your code running. Occam's razor would suggest it's RDP that's making use of the cores.
Besides, if you're doing File.Exists, the thread's going to be blocking on disk I/O anyway, if there's a point where it's putting a serious burden on the CPU, it won't be when it's just done that.
Finally, if you haven't done anything nuts like up the process priority from Normal, then it's going to share the cores with other processes anyway. It might be a bit bad if it falls into a tight loop, but even then the scheduler should prevent it doing too much harm on its own. All the more so with the more recent versions of Windows, and if you have more than one core.
Edit: Actually, scratch all that. Why poll in a loop yourself rather than in response to a FileSystemWatcher event. Set one or more
FileSystemWatcher
s to watch directory(s) of interest, and then poll for the specific file existence changes you care about in response to that. Less work for the code, and should be more responsive too.感谢您提供的所有答案,但我会尝试提供我自己的答案。
此时我不需要更改架构,并且任何使用任何数量的
Sleep()
的尝试都会失败。除了 SO 之外,我还搜索了一些其他网站,并发现了一个线程,其中 Jon Skeet 建议使用Monitor
来发出信号。这启发我尝试将
AutoResetEvent
的Sleep
更改为WaitOne
,我只会将其用作睡眠的替代方案,因为看起来,在我的情况下不起作用。尝试了一下,成功了!
Thank you for all the answers provided, but I'll try to provide one of my own.
I don't need architecture change at this point, and any attempts to use any amount of
Sleep()
failed. I searched a little other sites besides SO, and found one thread in which Jon Skeet suggests usage ofMonitor
to signal around.This inspired me to try and change the
Sleep
toWaitOne
ofAutoResetEvent
, which I'll use only as alternative to sleeping which, as it seems, doesn't work under my circumstances.Tried it, and it worked!
别睡觉。将线程优先级设置为 IDLE。
接下来的事情是确定每个进程的 CPU 消耗,这样您就不会迷失方向。打开 Perfmom.exe 并查看
Process(*)\(*)
对象(所有实例)。然后,您可以检查每个进程的% Processor Time
和% User Time
,并确定 RDP 关闭时谁在使用 18%。顺便说一句,与其
一遍又一遍地整理相同的目录
,为什么不使用 更改通知机制?Don't sleep. Set your thread priority to IDLE instead.
Next thing is to identify the CPU consumption per process, so you don't chase a red herring. Open the Perfmom.exe and look at the
Process(*)\(*)
object (all instances). Then you can inspect the% Processor Time
and% User Time
for each process and identify who is using the 18% when RDP is closed.As a side note, rather than
shuffling same directories over and over again
, why not use the change notifications mechanism instead?Sleep 10 只有 10 毫秒——所以你真的很接近屈服并回去工作了。
我的猜测是,当您登录时,有足够多的事情发生,您的线程不会立即重新安排,因此它实际上最终处于非活动状态超过 10 毫秒(我想我读到的最大分辨率顺便说一句,睡眠是 100 米尔)。但是,当您未使用 RDP 时,线程可更频繁地重新调度,因此会消耗更多 CPU。
要进行测试,请尝试将睡眠持续时间增加到 500(0.5 秒)或 1000 左右,以获得明显的睡眠时间。
另一个测试是在一个不做任何事情的循环中抛出另一个线程,看看当您强制 CPU 忙碌时,您的 file.exists 线程是否会正常产生。
Sleep 10 is only 10 milliseconds -- so you are really close to just yielding and going back to work.
My guess would be that when you are logged on, there is enough going on that your thread doesn't get rescheduled immediately, so that it really ends up being inactive for more than 10 milliseconds (and I think I read that the max resolution of the sleep is 100 mills, btw). However, when you are not RDP'd, the thread becomes available for rescheduling far more frequently, so it burns more CPU.
To test, try increasing your sleep duration to 500 (0.5 sec), or 1000, or so, to give you a noticeable sleep period.
Another test, would be to throw down another thread in a do-nothing loop and see if your file.exists thread yields respectfully when you are forcing the CPU to be busy.