기존의지도와 도움 답변 보완 할 수 있는 방법 사용하는 경우 와 성능 비교를 .
파이프 라인 외부 에서 (PSv3 +)를 사용하십시오.
$ objects . 이름
rageandqq의 대답 에서 알 수 있듯이 구문 상 단순하고 훨씬 빠릅니다 .
A의 파이프 라인 결과는 추가 처리되어야 곳에 나 결과는 전체로서 메모리에 맞지 않는 용도 :
$ objects | Select-Object -ExpandProperty 이름
- 그 필요성
-ExpandProperty
은 Scott Saad의 답변에 설명되어 있습니다.
- 일대일 처리의 일반적인 파이프 라인 이점을 얻을 수 있습니다. 이는 일반적으로 결과를 즉시 생성하고 메모리 사용을 일정하게 유지합니다 (결국 결과를 메모리에 수집하지 않는 한).
- 거래 :
들어 작은 입력 컬렉션 (배열), 당신은 아마 차이를 통지하지 않습니다 때로는 명령을 입력 할 수있는, 특히 명령 행에, 그리고 쉽게 더 중요하다.
여기이고 쉬운 타입 대안 그러나이며 느린 접근 방식 ; 연산 문 (PSv3 +) 이라고하는 단순화 된 ForEach-Object
구문을 사용 합니다 . 예를 들어 다음 PSv3 + 솔루션은 기존 명령에 쉽게 추가 할 수 있습니다.
$objects | % Name # short for: $objects | ForEach-Object -Process { $_.Name }
완벽을 기하기 위해 : 이 기사 에서보다 포괄적으로 설명 된 잘 알려진 PSv4 + .ForEach()
어레이 방법 은 또 다른 대안입니다 .
# By property name (string):
$objects.ForEach('Name')
# By script block (more flexibility; like ForEach-Object)
$objects.ForEach({ $_.Name })
이 접근법은 파이프 라인 로직이 적용 되지 않는다는 점을 제외하고는 동일한 트레이드 오프를 갖는 멤버 열거와 유사합니다 . 파이프 라인보다 눈에 띄게 빠르지 만 속도 는 약간 느립니다 .
이름 으로 단일 속성 값을 추출하는 경우 ( 문자열 인수) 경우이 솔루션은 멤버 열거와 동등합니다 (후자는 구문 상 단순하지만).
스크립트 블록 변이체는 , 임의의 허용 변환 ; 그것이 빠른 - 모든 -에 - 메모리 -에서 - 번 - 파이프 라인 기반의 대안 ForEach-Object
cmdlet을 ( %
) .
다양한 접근 방식의 성능 비교
다음은 10 개의 실행에 걸쳐 평균화 된 객체 컬렉션을 기반으로 한 다양한 접근 방식에 대한 샘플 타이밍 입니다 . 절대 숫자는 중요하지 않으며 많은 요소에 따라 다르지만 상대적인 감각을 가져야합니다.10,000
성능에 합니다 (타이밍은 단일 코어 Windows 10 VM에서 제공됨).
중대한
상대적인 성능은 입력 오브젝트의 인스턴스인지에 따라 달라 일반적인 .NET 형식 (출력 등에 의해, 예를 들면 Get-ChildItem
OR) [pscustomobject]
인스턴스 (의한 출력으로서, 예를 들면 Convert-FromCsv
).
그 이유는 [pscustomobject]
PowerShell에서 속성을 동적으로 관리하기 때문에 정적으로 정의 된 일반 .NET 유형의 일반 속성보다 빠르게 액세스 할 수 있기 때문입니다. 두 시나리오 모두 아래에 설명되어 있습니다.
이 테스트에서는 전체 메모리 내 전체 컬렉션을 입력으로 사용하여 순수한 속성 추출 성능에 중점을 둡니다. 스트리밍 cmdlet / 함수 호출을 입력으로 사용하면 호출 내부에 소요 된 시간이 대부분의 시간을 차지할 수 있으므로 성능 차이는 일반적으로 훨씬 덜 두드러집니다.
간결성 %
을 위해 ForEach-Object
cmdlet 에는 별칭 이 사용됩니다 .
일반 .NET 유형과 [pscustomobject]
입력 모두에 적용되는 일반 결론 :
멤버 열거 형 ( $collection.Name
)과 foreach ($obj in $collection)
솔루션은 가장 빠른 파이프 라인 기반 솔루션보다 10 배 이상 빠릅니다.
놀랍게도이 GitHub 문제를 보는 % Name
것보다 훨씬 더 나쁜 성능을 % { $_.Name }
보입니다 .
여기서 PowerShell Core는 Windows Powershell보다 성능이 뛰어납니다.
일반 .NET 유형의 타이밍 :
- PowerShell Core v7.0.0-preview.3
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.005
1.06 foreach($o in $objects) { $o.Name } 0.005
6.25 $objects.ForEach('Name') 0.028
10.22 $objects.ForEach({ $_.Name }) 0.046
17.52 $objects | % { $_.Name } 0.079
30.97 $objects | Select-Object -ExpandProperty Name 0.140
32.76 $objects | % Name 0.148
- Windows PowerShell v5.1.18362.145
Comparing property-value extraction methods with 10000 input objects, averaged over 10 runs...
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.012
1.32 foreach($o in $objects) { $o.Name } 0.015
9.07 $objects.ForEach({ $_.Name }) 0.105
10.30 $objects.ForEach('Name') 0.119
12.70 $objects | % { $_.Name } 0.147
27.04 $objects | % Name 0.312
29.70 $objects | Select-Object -ExpandProperty Name 0.343
결론 :
- PowerShell Core 에서는
.ForEach('Name')
분명히 성능이 뛰어납니다 .ForEach({ $_.Name })
. 흥미롭게도 Windows PowerShell에서는 후자가 조금 더 빠르지 만 더 빠릅니다.
[pscustomobject]
인스턴스 타이밍 :
- PowerShell Core v7.0.0-preview.3
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.006
1.11 foreach($o in $objects) { $o.Name } 0.007
1.52 $objects.ForEach('Name') 0.009
6.11 $objects.ForEach({ $_.Name }) 0.038
9.47 $objects | Select-Object -ExpandProperty Name 0.058
10.29 $objects | % { $_.Name } 0.063
29.77 $objects | % Name 0.184
- Windows PowerShell v5.1.18362.145
Factor Command Secs (10-run avg.)
------ ------- ------------------
1.00 $objects.Name 0.008
1.14 foreach($o in $objects) { $o.Name } 0.009
1.76 $objects.ForEach('Name') 0.015
10.36 $objects | Select-Object -ExpandProperty Name 0.085
11.18 $objects.ForEach({ $_.Name }) 0.092
16.79 $objects | % { $_.Name } 0.138
61.14 $objects | % Name 0.503
결론 :
[pscustomobject]
입력 .ForEach('Name')
으로 스크립트 블록 기반 변형을 훨씬 능가 하는 방법에 주목하십시오 .ForEach({ $_.Name })
.
마찬가지로 [pscustomobject]
입력은 파이프 라인 기반의 Select-Object -ExpandProperty Name
속도를 향상 시킵니다 ( Windows PowerShell의 경우 사실상). .ForEach({ $_.Name })
PowerShell Core의 경우 여전히 약 50 % 느립니다.
요컨대 : 홀수의 제외 % Name
와, [pscustomobject]
등록 정보를 참조하는 스트링 계 메소드 스크립트 블록 기반 것들 뛰어나다.
테스트 소스 코드 :
노트 :
$count = 1e4 # max. input object count == 10,000
$runs = 10 # number of runs to average
# Note: Using [pscustomobject] instances rather than instances of
# regular .NET types changes the performance characteristics.
# Set this to $true to test with [pscustomobject] instances below.
$useCustomObjectInput = $false
# Create sample input objects.
if ($useCustomObjectInput) {
# Use [pscustomobject] instances.
$objects = 1..$count | % { [pscustomobject] @{ Name = "$foobar_$_"; Other1 = 1; Other2 = 2; Other3 = 3; Other4 = 4 } }
} else {
# Use instances of a regular .NET type.
# Note: The actual count of files and folders in your home dir. tree
# may be less than $count
$objects = Get-ChildItem -Recurse $HOME | Select-Object -First $count
}
Write-Host "Comparing property-value extraction methods with $($objects.Count) input objects, averaged over $runs runs..."
# An array of script blocks with the various approaches.
$approaches = { $objects | Select-Object -ExpandProperty Name },
{ $objects | % Name },
{ $objects | % { $_.Name } },
{ $objects.ForEach('Name') },
{ $objects.ForEach({ $_.Name }) },
{ $objects.Name },
{ foreach($o in $objects) { $o.Name } }
# Time the approaches and sort them by execution time (fastest first):
Time-Command $approaches -Count $runs | Select Factor, Command, Secs*
$results = @($objects | %{ $_.Name })
. Scott 의 대답이 일반적으로 더 좋다고 생각하지만 명령 줄에 입력하는 것이 더 편리 할 수 있습니다 .