PowerShell -检查'ctrl+c' -快速

k0pti3hp  于 2023-04-30  发布在  Shell
关注(0)|答案(1)|浏览(211)

我有一个PowerShell脚本,它24 x7运行,直到用户按下crtl+c执行受控关机。
我使用这个简单的函数来检查是否按下了Ctrl+C键

function fnTestForCtrlC
{
  ## Stops Ctrl+C from exiting this function
  [console]::TreatControlCAsInput = $true

  if ($Host.UI.RawUI.KeyAvailable -and (3 -eq [int]$Host.UI.RawUI.ReadKey("AllowCtrlC,IncludeKeyUp,NoEcho").Character))
  {
    # Initiate an orderly shutdown here 
  }
}

代码运行良好,但在做一些性能调优时,我发现每次调用它大约需要100 ms。由于脚本几乎连续地检查ctrl+c,这对整个脚本的性能有很大的影响。
为什么这个函数要花这么长时间来执行,有没有更好的(i。(2)更快的方法做同样的事情。
更新-仍然有这个问题。我已经把代码从函数移到了主循环中。...

$swCtrlC.start()
  $script:cntCtrlC++
  if ($Host.UI.RawUI.KeyAvailable -and (3 -eq [int]$Host.UI.RawUI.ReadKey("AllowCtrlC,IncludeKeyUp,NoEcho").Character))
  {
    # Initiate an orderly shutdown here 
  }
  $swCtrlC.stop()

$swCtrlC是秒表,$script:cntCtrlC是计数器。我将一个除以另一个,得到大约80 ms的整体数字。
因此,即使在从函数的开销中删除了测试条件之后,这个简单的检查。...

if ($Host.UI.RawUI.KeyAvailable -and (3 -eq [int]$Host.UI.RawUI.ReadKey("AllowCtrlC,IncludeKeyUp,NoEcho").Character))

需要80 ms或更长时间。
只是为了澄清根本问题。我并不特别关心ctrl+c的测试,我只是在寻找一种方法,让用户可以干净地退出一个连续的循环,而不必浪费太多时间检查用户输入。

atmip9wb

atmip9wb1#

从你目前展示的内容来看,没有太多的改进空间,你能做的最好的就是不使用函数,把你的if条件放在循环中,在脚本的顶部只对TreatControlCAsInput赋值一次。在PowerShell中调用函数或脚本块有点昂贵,这在PowerShell脚本性能注意事项中有所暗示。
试试这个测试:

$tests = @{
    'Function Invocation' = {
        [console]::TreatControlCAsInput = $true

        function fnTestForCtrlC {
            if ($Host.UI.RawUI.KeyAvailable -and 3 -eq $Host.UI.RawUI.ReadKey('AllowCtrlC,IncludeKeyUp,NoEcho').Character) {
                Write-Host 'Ctrl+C was pressed'
            }
        }

        $i = 0
        while($i++ -le 100000) {
            fnTestForCtrlC
        }
    }

    'If condition' = {
        [console]::TreatControlCAsInput = $true

        $i = 0
        while($i++ -le 100000) {
            if ($Host.UI.RawUI.KeyAvailable -and 3 -eq $Host.UI.RawUI.ReadKey('AllowCtrlC,IncludeKeyUp,NoEcho').Character) {
                Write-Host 'Ctrl+C was pressed'
            }
        }
    }
}

$tests.GetEnumerator() | ForEach-Object {
    [pscustomobject]@{
        Test = $_.Key
        Time = (Measure-Command { & $_.Value }).TotalMilliseconds
    }
}

相关问题