关于多线程:C#中的Thread.Sleep(1)有什么影响?

c#multithreading

What is the impact of Thread.Sleep(1) in C#?

在Windows窗体应用程序中,调用Thread.Sleep(1)有什么影响,如以下代码所示:

public Constructor()
{
    Thread thread =new Thread(Task);
    thread.IsBackground=true;
    thread.Start();
}

privatevoid Task()
{
    while(true)
    {
        // do something
        Thread.Sleep(1);
    }
}

该线程会占用所有可用的CPU吗?

我可以使用什么配置技术来测量此线程的CPU使用率(任务管理器除外)?

相关讨论

到目前为止,所有答案都表明效果可以忽略不计,但是您能否澄清一下您要完成的工作?
我只是想看看我的GUI应用程序是否由于1ms的短延迟而将所有时间都花在了这个线程上。

如前所述,您的循环不会占用CPU。

但是请注意:Windows不是实时操作系统,因此您不会从Thread.Sleep(1)每秒获得1000次唤醒。如果您未使用timeBeginPeriod设置最低分辨率,则大约每15毫秒唤醒一次。即使将最低分辨率设置为1

ms,您仍然只能每3-4 ms唤醒一次。

为了获得毫秒级的计时器粒度,您必须使用Win32多媒体计时器(C#包装器)。

相关讨论

您能否举一个在C#中设置timeBeginPeriod的示例?
pinvoke.net/default.aspx/winmm.timeBeginPeriod根据MSDN文档,timeBeginPeriod应该与timeEndPeriod调用匹配。另请注意,"此功能会影响Windows的全局设置。"并会影响系统性能。

不,它不会占用CPU,它只会使您的线程至少暂停那么长时间。线程暂停时,操作系统可以安排另一个不相关的线程来使用处理器。

相关讨论

不过,这会不必要地占用大量CPU时间。
@Joel如何/为什么会花费更多时间而不是一段时间(true){i ++;或在CPU使用率方面是否基本相同?
与使用i ++相比,在现代CPU上1ms的睡眠是永恒的。
@Joel相对于具有10个功能的计算器的总可用CPU时间,是的,这将占用大量的CPU时间。相对于过去十年中制造的任何机器的可用CPU时间,它大约使用零CPU时间。

如上所述的Thread.Sleep(1)不会占用CPU。

这是线程休眠(或多或少)时发生的情况:

Thread.Sleep转换为系统调用,进而触发陷阱(使操作系统能够控制的中断)
操作系统检测到睡眠调用,并将您的线程标记为已阻止。
在内部,操作系统会保留需要唤醒的线程列表以及何时应唤醒线程。
由于线程不再使用CPU,因此OS ...
如果父进程没有用完所有时间片,则OS将安排该进程的另一个线程执行。
否则,另一个进程(或空闲进程)将开始执行。
时间到了,您的线程将被再次安排执行,这并不意味着它将自动开始执行。

最后一点,我不完全知道您在做什么,但似乎您正在尝试扮演调度程序的角色,也就是说,要让CPU有时间做其他事情。

在少数情况下(确实很少),可能没问题,但是大多数情况下,您应该让调度程序执行其工作,它可能比您了解的更多,并且可以使工作变得更好。


应避免睡眠时间太短,因为在重新分配信号时,放弃其时间片的线程会获得优先级提升,这可能导致高上下文切换。 在多线程/服务器应用程序中,由于线程在争夺CPU时间,因此这可能导致颠簸效果。 而是依赖异步函数和同步对象,例如关键部分或互斥体/信号量。


正如鲍勃·纳德勒(Bob Nadler)所述,Thread.Sleep(1)不能保证1ms的睡眠时间。

这是一个使用Win32多媒体计时器强制睡眠1毫秒的示例。

    [DllImport("winmm.dll")]
    internalstaticexternuint timeBeginPeriod(uint period);
    [DllImport("winmm.dll")]
    internalstaticexternuint timeEndPeriod(uint period);

    timeBeginPeriod(1);
    while(true)
    {
        Thread.Sleep(1);// will sleep 1ms every time
    }
    timeEndPeriod(1);

在C#GUI应用程序中对此进行测试,我发现该应用程序使用了大约50%的CPU。

有关此主题的更多讨论,请参见以下论坛主题:

http://www.dotnet247.com/247reference/msgs/57/289291.aspx


这是我的很多搜索中提到的旧线程,但是Win7有一个新的调度程序,其行为似乎与上面的有所不同。

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading;

namespace ConsoleApplication2
{
    class Program
    {
        staticvoid 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。因此,在1毫秒的时间内使用1ms的睡眠,我得到了946个唤醒。这非常接近1ms。

第二部分询问每1ms进行1000次睡眠事件需要多长时间。我有1034ms。同样,将近1ms。

这是在使用.Net 4.0的1.8ghz core2duo + Win7上

编辑:记住,sleep(x)并不意味着此时醒来,它意味着不早于这次唤醒我。不保证。虽然,您可以增加线程的优先级,并且Windows应该在较低优先级的线程之前安排线程。

相关讨论

添加有关Win 7调度程序的注释。我运行了Bengies示例" namespace ConsoleApplication2"的帖子,它报告了65和15600,指示约15毫秒的步长。这是一个运行.NET 3.5,Win 7的双重3.33Mhx。奇怪的是,昨天我的日志中有些代码的睡眠(1)接近1ms,就像他的帖子所声称的那样。我的结论是我的机器上有些设置或配置已更改,但我无法有或没有调试器,在调试或发布模式下的答案相同。我没有使用开始/结束时间周期。机器上的负载很小

不,不会。您几乎看不到它。在每秒不到1000次的某个位置,该线程将唤醒,几乎什么也不做,然后再次休眠。

编辑:

我必须检查一下。在Java 1.5上运行,此测试

@Test
publicvoid 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使用率。

相关讨论

我怀疑这种情况是否会经常发生:关于睡眠的争论是最短的时间,而上下文切换花费的时间太长,无法获得足够的支持。
在现代多核系统上,1ms可能是很长的时间。我不知道此循环将如何实际运行?

不,它不会占用所有可用的CPU,因为当另一个线程有工作要做时,睡眠线程将由OS的调度程序关闭。


也看看这个:msdn论坛

usingSystem;
usingSystem.Diagnostics;
usingSystem.Runtime.InteropServices;
usingSystem.Threading;

namespace Test
{
    publicstaticclass Program
    {
        publicstaticvoid 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+"\
");
            }
        }

        [DllImport("winmm.dll", EntryPoint="timeBeginPeriod", SetLastError=true)]
        privatestaticexternuint TimeBeginPeriod(uint uMilliseconds);

        [DllImport("winmm.dll", EntryPoint="timeEndPeriod", SetLastError=true)]
        privatestaticexternuint TimeEndPeriod(uint uMilliseconds);
    }
}

一个线程一次最多只能占用一个(逻辑)CPU。而且1毫秒的睡眠不会占用您很多时间。不要流汗。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值