在Windows窗体应用程序中调用Thread.Sleep(1)
会产生什么影响,如下面的代码所示:
public Constructor()
{
Thread thread = new Thread(Task);
thread.IsBackground = true;
thread.Start();
}
private void Task()
{
while (true)
{
// do something
Thread.Sleep(1);
}
}
这个线程会占用所有可用的CPU吗?
我可以使用哪些分析技术来衡量此线程的CPU使用率(除了任务管理器)?
答案 0 :(得分:43)
如上所述,你的循环不会占用CPU。
但要注意:Windows 不是实时操作系统,因此您不每秒从Thread.Sleep获得1000次唤醒( 1)。如果您没有使用timeBeginPeriod来设置最低分辨率,那么每15毫秒就会唤醒一次。即使您已将最小分辨率设置为1 ms,您仍然只能每3-4毫秒唤醒一次。
为了获得毫秒级别的计时器粒度,您必须使用Win32多媒体计时器(C# wrapper)。
答案 1 :(得分:28)
不,它不会占用CPU,它会暂停至少那么长的线程。当您的线程暂停时,操作系统可以安排另一个不相关的线程来使用处理器。
答案 2 :(得分:19)
如上所述,Thread.Sleep(1)不会占用CPU。
以下是线程休眠时(或多或少)发生的事情:
最后一点,我并不完全知道你在做什么,但似乎你正试图扮演调度程序的角色,也就是说,睡觉为CPU提供时间做其他事情。
在少数情况下(确实很少)它可能没问题,但大多数情况下你应该让调度程序完成它的工作,它可能比你更了解,并且可以使工作比你做得更好。
答案 3 :(得分:4)
Bob Nadler提到Thread.Sleep(1)
不能保证1ms的睡眠时间。
以下是使用Win32多媒体计时器强制睡眠1毫秒的示例。
[DllImport("winmm.dll")]
internal static extern uint timeBeginPeriod(uint period);
[DllImport("winmm.dll")]
internal static extern uint timeEndPeriod(uint period);
timeBeginPeriod(1);
while(true)
{
Thread.Sleep(1); // will sleep 1ms every time
}
timeEndPeriod(1);
在C#GUI应用程序中对此进行测试,我发现应用程序使用了大约50%的CPU。
有关此主题的更多讨论,请参阅以下论坛主题:
答案 4 :(得分:4)
应该避免小的睡眠时间,因为放弃时间片的线程在重新调整时会获得优先级提升,这可能导致高上下文切换。在多线程/服务器应用程序中,由于线程正在争夺CPU时间,这可能会导致颠簸效应。相反,依赖于异步函数和同步对象,例如关键部分或互斥锁/信号量。
答案 5 :(得分:3)
这是我的很多搜索中出现的一个旧线程,但Win7有一个新的调度程序,并且看起来与上面的行为不同。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
DateTime dtEnd = DateTime.Now.AddSeconds(1.0);
int i = 0;
while (DateTime.Now < dtEnd)
{
i++;
Thread.Sleep(1);
}
Console.WriteLine(i.ToString());
i = 0;
long lStart = DateTime.Now.Ticks;
while (i++ < 1000)
Thread.Sleep(1);
long lTmp = (DateTime.Now.Ticks - lStart) / 10000;
Console.WriteLine(lTmp.ToString());
Console.Read();
}
}
}
使用上面的代码,我的第一个结果给出了946.所以在使用1ms睡眠的1秒的时间跨度中,我得到946个唤醒。这非常接近1毫秒。
第二部分询问每次1毫秒进行1000次睡眠事件需要多长时间。我有1034ms。再过近1ms。
这是使用.Net 4.0的1.8ghz core2duo + Win7
编辑:记住,睡眠(x)并不意味着此时醒来,这意味着不要早于此时唤醒我。这不保证。虽然,您可以增加线程的优先级,Windows应该在优先级较低的线程之前安排线程。
答案 6 :(得分:2)
不,它不会占用所有可用的CPU,因为当另一个线程有工作要做时,操作系统的调度程序将关闭一个休眠线程。
答案 7 :(得分:2)
不,它不会。你几乎看不到它。在某个小于1000次的情况下,这个线程会在醒来之前醒来,并且在再次睡觉之前几乎不做任何事情。
编辑:
我必须检查。在Java 1.5上运行,这个测试
@Test
public void testSpeed() throws InterruptedException {
long currentTime = System.currentTimeMillis();
int i = 0;
while (i < 1000)
{
Thread.sleep(1);
i++;
}
System.out.println("Executed in " + (System.currentTimeMillis() - currentTime));
}
在我的3ghz机器上每秒大约有500次睡眠。我认为C#应该是相同的。我假设有人会用C#号码报告这个非常重要的真实世界基准。顺便说一下,没有可观察到的CPU使用情况。
答案 8 :(得分:0)
线程一次最多只能占用一个(逻辑)CPU。 1毫秒的睡眠不会被占用。不要出汗。
答案 9 :(得分:0)
还要看一下:msdn forum
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace Test
{
public static class Program
{
public static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
for (int i = 0; i < 10; ++i)
{
sw.Reset();
sw.Start();
Thread.Sleep(50);
sw.Stop();
Console.WriteLine("(default) Slept for " + sw.ElapsedMilliseconds);
TimeBeginPeriod(1);
sw.Reset();
sw.Start();
Thread.Sleep(50);
sw.Stop();
TimeEndPeriod(1);
Console.WriteLine("(highres) Slept for " + sw.ElapsedMilliseconds + "\n");
}
}
[DllImport("winmm.dll", EntryPoint="timeBeginPeriod", SetLastError=true)]
private static extern uint TimeBeginPeriod(uint uMilliseconds);
[DllImport("winmm.dll", EntryPoint="timeEndPeriod", SetLastError=true)]
private static extern uint TimeEndPeriod(uint uMilliseconds);
}
}