有没有办法让powershell脚本在纳秒内睡眠?

时间:2015-06-12 00:04:58

标签: powershell

我使用以下PowerShell脚本生成事件并模拟不同的系统负载。当$sleepIntervalInMilliSeconds=0时,CPU使用率为100%。

然后,$sleepIntervalInMilliSeconds >= 1的任何值的CPU使用率都相似(56%)。

我认为脚本需要以纳秒而不是毫秒的速度睡眠,以便我可以控制CPU负载为70%,80%90%。

有办法做到这一点吗?浮点数< 1似乎不起作用。感谢任何线索。

Param(
  [int]$sleepIntervalInMilliSeconds = 0
)

$eventGenScript = {
  $logName = "TestLog"
  $sourceName = "TestSource"

  while($true) {
    Write-EventLog -LogName $logName -Source $sourceName -Message "perfLog" -EventId 0 -EntryType information
    Start-Sleep -Milliseconds $using:sleepIntervalInMilliSeconds
  }
}

$threadCount = 2

for($i=0; $i -lt $threadCount; $i++)
{
  Start-Job $eventGenScript  
}

read-host "type a key to exit."

1 个答案:

答案 0 :(得分:2)

我不认为自己是操作系统调度方面的专家,但通常它应该像这样工作:

具有抢占式多任务处理模型的操作系统通过为进程(线程)提供可用于执行的时间片(或量子)来工作。它的流程'然后选择消耗所有分配的时间(导致100%的CPU消耗)或仅消耗部分时间片并将其余部分返回给OS(通过调用某种sleep函数)。当完全消耗的时间片获得控制并将其传递给另一个线程时,它也有机会运行。此过程一直持续到您关闭计算机为止。这就是"调度"。多核CPU使问题复杂化,因为在任何一个时刻都可以有多个时间片。由于单线程在任何时刻都不能消耗超过1个时间片,因此单线程进程不能在多核CPU上产生100%的负载(除非你运行它们很少)。时间片大小通常具有固定的大小,不能太短(它会导致很多CPU浪费在线程之间切换)或者太长(因为进程会降低响应速度)。如果没有任何内容可以运行,则会将时间片给予将CPU切换到低功耗状态的特殊系统进程(Windows中的系统空闲进程)。

Start-Sleep cmdlet本质上就是我上面提到的sleep调用,它告诉操作系统:"我放弃参与调度n毫秒",这意味着您的进程只能在时间片的粒度上选择睡眠周期。基本上,你唯一的选择就是你要跳过多少时间片(再次,不能保证在这么长时间后才能完全唤醒过程)。

由于您无法以所需的粒度控制睡眠时间,因此您可以尝试控制在时间片中消耗的时间量。首先,让我们忘记Write-EventLog使用无用信息的洪水事件日志并做一些更简单的事情。

while ($true) {}
没有机身的无限循环完全消耗了我的4核CPU的1个内核,产生25%的CPU负载(其他3个内核空闲)。我们可以将它作为脚本块并在后台运行几次:

$el = { while ($true) {} };
$numCores = (Get-WmiObject -Class Win32_ComputerSystem).NumberOfLogicalProcessors;
$jobs = 1..$numCores | ForEach-Object { Start-Job -ScriptBlock $el };
Start-Sleep -Seconds 30
$jobs | Remove-Job -Force

我们开始无休止地循环的后台作业,每个核心一个作业,睡30秒,然后杀死它们。我们可以在具有任意数量内核的系统上产生100%的CPU负载。现在是时候让它消耗更少的CPU。要做到这一点,我们将在无限循环中运行有限循环然后再睡一会儿。现在,应该仔细挑选有限循环的长度,并且它将是非常系统的

$loopIterations = 24000;

$el = 
{
    while ($true) 
    {
        for ($i = 0; $i -lt $args[0]; ++$i){}
        Start-Sleep -Milliseconds 1
    } 
};
$numCores = (Get-WmiObject -Class Win32_ComputerSystem).NumberOfLogicalProcessors;
$jobs = 1..$numCores | ForEach-Object { Start-Job -ScriptBlock $el -ArgumentList $loopIterations};
Start-Sleep -Seconds 30
$jobs | Remove-Job -Force

此代码在我的系统上占用90%的CPU。你必须在它上面进行调整,以便将CPU加载到你想要的水平。