我试图测量一些在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
这怎么可能?
答案 0 :(得分:3)
事实证明,根据PowerShell团队成员对this related GitHub issue的反馈,问题通常是关于(隐式)点源 ( (例如,直接调用表达式)与 在子范围内运行 ,例如使用&
,调用运算符,或者在当前情况下,带有Invoke-Command -ScriptBlock
。
在子范围内运行可避免在(隐式)点源搜索时执行变量查找。
因此,从Windows PowerShell v5.1 / PowerShell Core 6.2开始,您可以通过简单地通过& { ... }
调用无副作用表达式来加速它们>,在子作用域中(考虑到创建新作用域涉及额外工作,这有点违反直觉):
也就是说,此优化可用于不希望直接(直接)修改调用者变量的表达式。
以下简化的代码使用foreach
表达式循环执行一百万次(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