给定一个名为
$derivedValues
的哈希表和一个需要变量扩展的变量,我看到了一些有趣的性能问题。
给定:
$rule.opnd1 = 'uninstallString'
$rule.opnd2 = 'MsiExec.exe /X$($_.keyGUID)'
$filteredKeys.Where({$_.($rule.opnd1) -eq $ExecutionContext.InvokeCommand.ExpandString($rule.opnd2)})
我取得了良好的表现。千分之几秒。但是当要展开的变量不是
$_
比如
$rule.opnd1 = 'displayName'
$rule.opnd2 = '$($derivedValues.displayName)'
性能真的很差。轻松接近半秒。我假设它与引用“父”范围内的
$derivedValues
相关,如果你愿意的话,与按定义在闭包范围内定义的 $_
相比。
我想知道的是,有没有办法将
$derivedValues
变量实际传递到闭包中,以便变量扩展始终是本地范围?如果是这样,这可能会提高性能吗?我知道这是一个奇怪的场景,所以如果有一种方法,但没有人知道它是否会有所帮助,因为没有人需要做这样的事情,那么,我会报告回来。 :)
ScriptBlock.InvokeWithContext
传入要由比较表达式脚本块求值的变量。
之前分享了一个示例来展示它如何使用示例对象工作:
# supposing this object is `$_`
$inputObject = [pscustomobject]@{ displayName = 'test' }
# this object would be the value of `opnd2`
$derivedValues = [pscustomobject]@{ displayName = 'test' }
# example object of what `$rule` would be
$rule = [pscustomobject]@{
opnd1 = 'displayName'
opnd2 = '$derivedValues.displayName'
}
# define the variables passed-in to the expression
$variables = [System.Collections.Generic.List[psvariable]]@(
[psvariable]::new('_', $inputObject)
[psvariable]::new('rule', $rule)
[psvariable]::new('derivedValues', $derivedValues))
# define the comparison expression
$expression = { $_.($rule.opnd1) -eq $derivedValues.displayName }
# evaluate it with the context
$expression.InvokeWithContext($null, $variables)[0]
上面显示,比较
$_.($rule.opnd1) -eq $derivedValues.displayName
与传入变量的计算结果为 true
。
进一步提高性能的下一步是使用带有
foreach
条件的 if
循环,而不是本身非常慢的 .Where
。使用 foreach
循环,我将在本示例中使用 $_
,而不是将 $key
传递到上下文:
# supposing this object is `$filteredKeys`
$filteredKeys = 0..10 | ForEach-Object { [pscustomobject]@{ displayName = $_ } }
# this object would be the value of `opnd2`
$derivedValues = [pscustomobject]@{ displayName = 5 }
# example object of what `$rule` would be
$rule = [pscustomobject]@{
opnd1 = 'displayName'
opnd2 = '$derivedValues.displayName'
}
# define the variables passed-in to the expression
$variables = [System.Collections.Generic.List[psvariable]]@(
[psvariable]::new('key', $null)
[psvariable]::new('rule', $rule)
[psvariable]::new('derivedValues', $derivedValues))
# define the comparison expression
$expression = { $key.($rule.opnd1) -eq $derivedValues.displayName }
foreach ($key in $filteredKeys) {
# Gets the first `psvariable` and sets the value to the current item in the loop
$variables[0].Value = $key
if ($expression.InvokeWithContext($null, $variables)[0]) {
$key
}
}
# Outputs:
#
# displayName
# -----------
# 5