C# 中的 Thread.Sleep(1) 有啥影响?
Posted
技术标签:
【中文标题】C# 中的 Thread.Sleep(1) 有啥影响?【英文标题】:What is the impact of Thread.Sleep(1) in C#?C# 中的 Thread.Sleep(1) 有什么影响? 【发布时间】:2009-02-03 17:59:29 【问题描述】:在 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 使用率(任务管理器除外)?
【问题讨论】:
到目前为止的所有答案都表明效果可以忽略不计,但你能否澄清一下你试图用这个来完成什么? 我只是想看看我的 GUI 应用程序是否因为短暂的 1 毫秒延迟而将所有时间都花在了这个线程上。 【参考方案1】:如上所述,您的循环不会占用 CPU。
但请注意:Windows 不是实时操作系统,因此您将不会每秒从 Thread.Sleep 获得 1000 次唤醒( 1)。如果您没有使用timeBeginPeriod 设置您的最小分辨率,您将每 15 毫秒唤醒一次。即使您将最小分辨率设置为 1 毫秒,您仍然只会每 3-4 毫秒唤醒一次。
为了获得毫秒级计时器粒度,您必须使用 Win32 多媒体计时器 (C# wrapper)。
【讨论】:
你能举一个在C#中设置timeBeginPeriod的例子吗? pinvoke.net/default.aspx/winmm.timeBeginPeriod 根据 MSDN 文档,timeBeginPeriod 应该与 timeEndPeriod 调用相匹配。另请注意“此功能会影响全局 Windows 设置”。并且会影响系统性能。【参考方案2】:不,它不会占用 CPU,它只会暂停你的线程至少那么长时间。当您的线程暂停时,操作系统可以调度另一个不相关的线程来使用处理器。
【讨论】:
不过,这会不必要地占用大量 CPU 时间。 @Joel 如何/为什么会花费更多时间而不是一段时间(真的) i++; 还是在 CPU 使用率方面基本相同? 在现代 CPU 上,与使用 i++ 相比,1ms 的睡眠是永恒的。 @Joel 相对于 10 功能计算器的总可用 CPU 时间,是的,这将占用“很多”CPU 时间。相对于过去十年制造的任何机器的可用 CPU 时间,它将使用大约零 CPU 时间。【参考方案3】:Thread.Sleep(1) 如上所述不会占用 CPU。
当线程休眠(或多或少)时会发生以下情况:
Thread.Sleep 被转换为系统调用,进而触发陷阱(允许操作系统控制的中断) 操作系统检测到睡眠调用并将您的线程标记为阻塞。 操作系统在内部保留了需要唤醒的线程列表以及唤醒时间。 由于线程不再使用 CPU 操作系统... 如果父进程没有用完其所有时间片,操作系统将安排该进程的另一个线程执行。 否则另一个进程(或空闲进程)将开始执行。 时间到了,你的线程会被重新调度执行,但这并不意味着它会自动开始执行。最后一点,我不完全知道您在做什么,但您似乎正在尝试扮演调度程序的角色,也就是说,睡觉以为 CPU 提供时间来做其他事情。 .
在少数情况下(确实很少)可能没问题,但大多数情况下你应该让调度程序完成它的工作,它可能比你知道的更多,并且可以让工作比你能做的更好。
【讨论】:
【参考方案4】:应避免较短的睡眠时间,因为放弃其时间片的线程在重新发出信号时会获得优先级提升,这可能导致高上下文切换。在多线程/服务器应用程序中,这可能会导致抖动效应,因为线程正在争夺 CPU 时间。相反,请依赖异步函数和同步对象,例如临界区或互斥体/信号量。
【讨论】:
【参考方案5】:正如 Bob Nadler 提到的,Thread.Sleep(1)
不保证 1 毫秒的睡眠时间。
这是一个使用 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。
有关此主题的更多讨论,请参阅以下论坛主题:
http://www.dotnet247.com/247reference/msgs/57/289291.aspx
【讨论】:
【参考方案6】:这是一个旧线程,在我的很多搜索中都会出现,但 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 毫秒。
第二部分询问以 1ms 的时间完成 1000 个睡眠事件需要多长时间。我得到了 1034 毫秒。同样,将近 1 毫秒。
这是在 1.8ghz core2duo + Win7 上使用 .Net 4.0
编辑:记住,sleep(x) 并不意味着在这个时候醒来,它意味着不早于这个时候叫醒我。不能保证。不过,您可以提高线程的优先级,并且 Windows 应该在较低优先级的线程之前安排您的线程。
【讨论】:
关于 Win 7 调度程序的评论。我运行了 Bengie 的示例“命名空间 ConsoleApplication2”帖子,它报告了 65 和 15600,表示大约 15 毫秒的步骤。这是一个运行 .NET 3.5、Win 7 的双 3.33Mhx。奇怪的是,昨天我的日志中有一些代码显示 sleep(1) 更接近 1ms,就像他的帖子声称的那样。我的结论是我的机器上有一些设置或配置发生了变化,但我无法确定。在带有或不带有调试器的调试或发布模式下,答案相同。我没有使用开始/结束时间段。 ma上的负载很小【参考方案7】:不,它不会占用所有可用的 CPU,因为当另一个线程有工作要做时,操作系统的调度程序会关闭一个睡眠线程。
【讨论】:
【参考方案8】:不,不会。你几乎看不到它。大约每秒不到 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 使用率。
【讨论】:
我怀疑它是否会经常发生:睡眠的参数是最短时间,而上下文切换需要很长时间才能得到很多。 在现代多核系统上,1ms 是一个非常长的时间。我想知道这个循环实际上是如何运行的?【参考方案9】:一个线程一次最多只能占用一个(逻辑)CPU。并且 1 毫秒的睡眠不会占用太多时间。不要出汗。
【讨论】:
【参考方案10】:也看看这个: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);
【讨论】:
以上是关于C# 中的 Thread.Sleep(1) 有啥影响?的主要内容,如果未能解决你的问题,请参考以下文章
timeunit的sleep和thread的sleep有啥区别
C# 中的 Thread.Sleep():它是让实例化对象的线程休眠,还是让我从中调用方法的线程休眠?
使用 boost::this_thread::sleep_for() 和常规 sleep() 函数有啥区别?
selenium.wait()、selenium.wait(2000) 和 Thread.sleep(2000) 有啥区别? [复制]