Invoke-Command比命令本身更快?

问题描述 投票:5回答:1

我试图测量一些在PowerShell中写入文件的方法。毫无疑问,但我不明白为什么下面的第一个Measure-Command声明要比第二个声明执行更长的时间。

它们是相同的但在第二个中我写了一个脚本块发送到Invoke-Command,在第一个我只运行命令。

关于Invoke-Command速度的所有信息我都能找到关于远程处理的信息。

此块大约需要4秒钟:

Measure-Command {
    $stream = [System.IO.StreamWriter] "$PSScriptRoot\t.txt"
    $i = 0
    while ($i -le 1000000) {
        $stream.WriteLine("This is the line number: $i")
        $i++
    }
    $stream.Close() 
} # takes 4 sec

而下面的代码完全相同,但是在传递给Invoke-Command的脚本块中写入大约需要1秒钟:

Measure-Command {
    $cmdtest = {
        $stream = [System.IO.StreamWriter] "$PSScriptRoot\t2.txt"
        $i = 0
        while ($i -le 1000000) {
            $stream.WriteLine("This is the line number: $i")
            $i++
        }
        $stream.Close()
     }
     Invoke-Command -ScriptBlock $cmdtest
} # Takes 1 second

怎么可能?

powershell-v4.0 invoke-command
1个回答
4
投票

事实证明,根据来自this related GitHub issue的PowerShell团队成员的反馈,问题更普遍地涉及(隐式)点源(例如直接调用表达式)与在子范围内运行,例如&,呼叫操作员,或者在手头的情况下,与Invoke-Command -ScriptBlock

在子范围内运行可避免在(隐式)点源时执行的变量查找。

因此,从Windows PowerShell v5.1 / PowerShell Core 6.2开始,您可以通过在子范围内通过& { ... }调用它们来加速无副作用的表达式(有点反直觉,因为创建新范围涉及额外的工作):

也就是说,此优化可以与不希望修改调用者变量的表达式一起使用(直接)。

以下简化代码使用foreach表达式循环100万次(1e6)演示了这一点:

# REGULAR, direct invocation of an expression (a `foreach` statement in this case), 
# which is implicitly DOT-SOURCED
(Measure-Command { $result = foreach ($n in 1..1e6) { $n } }).TotalSeconds

# OPTIMIZED invocation in CHILD SCOPE, using & { ... }
# 10+ TIMES FASTER.
(Measure-Command { $result = & { foreach ($n in 1..1e6) { $n } } }).TotalSeconds
© www.soinside.com 2019 - 2024. All rights reserved.