为什么空循环使用如此多的处理器时间?

如果我的代码中有一个空的while循环,例如:

while(true); 

它将使处理器使用率提高约25%。 但是,如果我执行以下操作:

 while(true) Sleep(1); 

它只会使用大约1%。

那为什么呢?

更新:感谢所有好的回复,但我想我真的应该问这个问题, 睡眠()后面的算法是什么? 这更像是我想知道的。

对于前者,必须由处理器检查条件true ,因为应用程序可能会获得焦点。 一旦应用程序获得处理器注意,它就会像任何其他循环条件一样检查true ,以查看循环中的下一条指令是否可以执行。 当然,循环中的下一条指令也是true 。 基本上,你迫使处理器不断地确定是否为真,这虽然是微不足道的,但是当执行时不断地使处理器陷入困境。

在后者中,处理器检查true一次,然后执行下一个语句。 在这种情况下,这是1ms等待。 由于1 ms远远大于检查true所需的时间,并且处理器知道它可以在此等待期间执行其他操作,因此您可以释放大量电量。

我猜你的多核处理器上有四个内核,这可以解释25%,因为你完全占用了一个处理繁忙循环的处理器,因为唯一的突破是当应用程序被延迟而另一个应用程序可以运行(但可能不会发生,具体取决于负载)。

当你让一个线程进入hibernate状态时,它允许操作系统进行其他操作,并且它知道何时至少返回并唤醒线程,因此它可以继续它的工作。

第一个连续使用CPU操作。 后者切换当前运行的线程的上下文,put处于睡眠模式,从而允许调度其他进程。

你有一台四核机器,对吗? 如果是这样,

 while(true); 

实际上是使用了100%的核心。

对于操作系统来说,您的程序似乎还有很多工作要做。 因此,操作系统让程序继续这项工作。 它无法区分你疯狂的程序编号和无用的无限循环。

 Sleep(1); 

另一方面明确地告诉操作系统你在下一毫秒内没有工作要做。 因此操作系统将停止运行您的程序并让其他程序运行。

空循环实际上不是空的。 一个循环本身至少是一个比较和跳回到比较。 现代CPU每秒可以执行数百万次这样的操作。

第二个循环中的sleep语句放弃对操作系统的控制至少1毫秒。 在此状态下,应用程序将被有效停止,并且不会继续处理。 停止x个时间量的结果减少了比较次数,因此减少了cpu每秒可执行的cpu时钟周期的百分比。

关于25%,支持超线程或多核处理器的英特尔处理器可能会污染性能统计数据。 空循环有效地顶住至少一个处理器核心。

在多核CPU不存在的那一天,用户确实需要多处理/任务。 有两种方法可以实现同时运行多个进程的错觉。

一种方法是以这样一种方式设计应用程序,即他们需要经常放弃对系统的控制,以便让其他进程运行一段时间。 在旧的Windows版本中就是这种情况。 如果给定的应用程序设计糟糕,以至于它没有放弃控制,或者陷入无限循环,那么整个PC都会被冻结。

毋庸置疑,这不是最好的方式,它被先发制人的多任务处理所取代。 这里指示可编程中断定时器以给定间隔中断正在运行的进程,以执行一些调度程序代码,使其他进程可以运行。

基本上,你有几个“进程调度程序”状态。 我将其中三个命名。 一:准备二:跑三:被阻止

仅存在这些状态/队列,因为处理器上的核心数量有限。 在Ready中 ,计划完全准备好执行的进程。 他们不必等待输入,时间等等。 在运行时,进程实际上“拥有”处理器,因此正在运行。 State Blocked表示您的进程在排队处理器之前等待事件发生。

当你继续测试while(true)时,你将你的进程保持在“ 就绪 ”队列中。 您的进程调度程序会给它一定的时间,过一会儿,将其从处理器中删除(将其放在“就绪”队列的后面)。 因此,您的流程将继续“回”到处理器上,让它保持忙碌状态。

当您执行“睡眠”语句时,在完成先决条件之前,您的进程将不会在进程中进行调度 – 在此特定情况下,只要在“sleep”命令之后经过的时间<= 1000 ms。

Sleep()在线程处于hibernate期间并没有真正做任何事情。 它将时间交给其他进程使用。 另一方面,循环不断检查条件是真还是假。

因为Sleep基本上告诉处理器切换上下文并让其他一些程序获得更多的CPU时间。

第二个中的睡眠有点像操作系统的进程调度程序的“收益”。

因为你要让处理器忙于评估循环结束。

使用Sleep实际上允许其他线程在CPU上执行,并且一个非常短的上下文切换看起来好像CPU在一段时间内是空闲的。

一个CPU每秒可以完成几十亿次操作。 这意味着空循环每秒运行mybe一百万次。 带有sleep语句的循环每秒只运行1000次。 在这种情况下,cpu每秒都会执行一些操作来执行其他操作。

假设我们有一个3GHz的cpu。 3Ghz = 3 000 000 000Hz – cpu可以每秒运行三次循环(简称)。

使用sleep语句,循环每秒执行1000次。 这意味着cpu负载是

1000/3 000 000 000 * 100 = 0.0001%

因为那会一直运行指令。

普通程序不会一直疯狂地运行指令。

例如,GUI程序只是闲置等待事件(例如键盘输入),

注意:闲置!= while(true);

它们仅在事件到达时运行指令,并且事件处理代码通常很小并且运行得非常快(否则,程序似乎没有响应)。 想象一下,你的应用每秒可以获得5次击键,需要多少CPU时间?

这就是普通进程不占用那么多CPU的原因。

现在,早些时候我说闲置与无限空循环不同。 这是为什么? 闲置意味着告诉操作系统你没有任何东西可以运行。

无限循环实际上要运行的东西(重复跳转指令)。

另一方面,没有任何东西可以运行基本上意味着操作系统甚至不会给你任何处理器时间,即使轮到你了。

程序闲置的另一个例子是加载文件:当你需要加载文件时,你基本上会向磁盘发送一个信号并等待它找到数据并将其加载到内存中。 在加载数据(几毫秒)时,进程只是空闲,什么都不做。

另一个处于空闲状态的进程实例是Sleep(1) ,这里明确告诉操作系统在指定时间过去之前不要给它任何cpu时间。