简短问题
使用以下方法是否有效/安全:
$SomeArray | ?{$_ -match $Pattern} | %{$Matches.CapturingGroupName}
而不是:
$SomeArray | %{if($_ -match $Pattern){$Matches.CapturingGroupName}}
您为什么要这样做?
where-object
或foreach-object
脚本块中有额外的代码,这些代码已知耗时(例如IO或网络操作)。更多信息
我编写了大量使用-match
(where-object
)过滤器中?{<#...#>}
语句的代码,然后在{{1}中引用$matches
(foreach-object
)语句。
在我第一次这样做之前,我测试了很多,以确保%{<#...#>}
变量始终为前一个匹配的结果;即确保在继续使用下一个元素之前使用管道不允许该变量更新。我甚至包括代码以确保它不受竞争条件的影响。
测试代码
$matches
$TestMax = 1000 #test 1000 times
$SleepMS = 1000 #wait 1 second between each test to allow the feeding match a headstart on the matches
$Evens = 1..(2*$TestMax) | %{"$_"} | ?{$_ -match '^(?<EvenNumber>.*[02468])$'} | %{Start-Sleep -Milliseconds $SleepMS; $matches.EvenNumber}
if ((Compare-Object $Evens (1..$TestMax | %{"$($_*2)"}) ) -eq $null) {":)"} else {":("}
来测试数字是否均匀(注意:此代码仅用于演示问题;我从未使用此方法来测试实际中的均匀度)-match
循环的开始,试图创建一个竞争条件,where-object
可以超越where-object
;因此在读取之前更改foreach-object
值。这可以按预期工作(即我们得到一个笑脸)。
为什么要关注?
我做了一些愚蠢的事......我在$matches
和sort-object
之间添加了一个where
(出于正当理由),在一个脚本阻止管道输入时是否存在竞争条件下一个(即使包括人为延迟)在添加其他块时也不会出现问题。我忘了的是foreach
必须先看到所有内容才能输出第一个结果;因此sort
将永远是最后一场比赛。
即。第3行现在是:
$matches
虽然这在使用$Evens = 1..(2*$TestMax) | %{"$_"} | ?{$_ -match '^(?<EvenNumber>.*[02468])$'} | sort | %{Start-Sleep -Milliseconds $SleepMS; $matches.EvenNumber}
时完全有意义,但这也意味着不能保证一个脚本块会跟随另一个脚本块;尽管它在我原来的测试中做到了。因此,只要我在sort
和where
之间不包含任何内容,这种行为(即我在原始问题中描述的内容)将始终如我所期望的那样是安全的。块;或者这只是一个等待咬我的假设?
更易读的测试代码版本
foreach