업데이트 -이 답변에서는 PowerShell 실행 영역의 프로세스 및 메커니즘과 이들이 멀티 스레드 비 순차 워크로드를 지원하는 방법에 대해 설명하지만 동료 PowerShell 애호가 인 Warren 'Cookie Monster'F 는이 같은 개념을 하나의 도구로 통합했습니다. 호출 된 -아래에서 설명하는 작업을 수행 한 후 가져온 모듈, 실제로 멋진 물건을 포함하여 로깅 및 준비된 세션 상태를위한 옵션 스위치로 확장했습니다 . 광택 한 솔루션을 구축하기 전에 체크 아웃 하는 것이 좋습니다 !Invoke-Parallel
병렬 런 스페이스 실행
피할 수없는 대기 시간 단축
원래의 특정 경우, 호출 된 실행 파일 /nowait
에는 작업 (이 경우 시간 재 동기화)이 자체적으로 완료되는 동안 호출 스레드를 차단 하는 옵션이 있습니다.
이렇게하면 발급자 관점에서 전체 실행 시간이 크게 단축되지만 각 컴퓨터에 대한 연결은 여전히 순차적으로 수행됩니다. 시간 초과 대기 누적으로 인해 액세스 할 수없는 여러 가지 머신 수에 따라 수천 개의 클라이언트에 순서대로 연결하는 데 시간이 오래 걸릴 수 있습니다.
단일 또는 몇 번의 연속 시간 초과가 발생할 경우 모든 후속 연결을 대기열에 넣지 않기 위해 명령을 연결하고 호출하는 작업을 별도의 PowerShell Runspace에 병렬로 실행하여 전달할 수 있습니다.
런 스페이스 란 무엇입니까?
실행 영역은 가상 컨테이너에서 파워 쉘 코드가 실행하고, 대표 / PowerShell은 문 / 명령의 관점에서 환경을 보유하고 있습니다.
넓은 의미에서 1 Runspace = 1 실행 스레드이므로 PowerShell 스크립트를 "멀티 스레드"하는 데 필요한 모든 Runspace 컬렉션은 병렬로 실행될 수 있습니다.
원래 문제와 같이 여러 실행 영역 명령을 호출하는 작업은 다음과 같이 나눌 수 있습니다.
- RunspacePool 만들기
- PowerShell 스크립트 또는 이에 상응하는 실행 코드를 RunspacePool에 할당
- 코드를 비동기 적으로 호출하십시오 (예 : 코드가 리턴 될 때까지 기다리지 않아도 됨)
RunspacePool 템플릿
PowerShell에는 [RunspaceFactory]
Runspace 구성 요소를 만드는 데 도움 이되는 형식 가속기 가 있습니다.
1. RunspacePool을 작성하고 다음을 수행 Open()
하십시오.
$RunspacePool = [runspacefactory]::CreateRunspacePool(1,8)
$RunspacePool.Open()
두 인수에 전달 CreateRunspacePool()
, 1
그리고 8
우리에게 효과적인 제공, 최소 및 주어진 시간에 실행할 수 실행 영역의 최대 수입니다 최대 병렬 처리 수준 (8)을.
2. PowerShell 인스턴스를 생성하고 실행 코드를 첨부 한 다음 RunspacePool에 할당합니다.
PowerShell의 인스턴스는 powershell.exe
프로세스 (실제로 호스트 응용 프로그램) 와 동일하지 않지만 실행할 PowerShell 코드를 나타내는 내부 런타임 개체입니다. [powershell]
유형 가속기를 사용하여 PowerShell 내에 새 PowerShell 인스턴스를 만들 수 있습니다 .
$Code = {
param($Credentials,$ComputerName)
$session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
Invoke-Command -Session $session -ScriptBlock {w32tm /resync /nowait /rediscover}
}
$PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument("computer1.domain.tld")
$PSinstance.RunspacePool = $RunspacePool
3. APM을 사용하여 PowerShell 인스턴스를 비동기 적으로 호출합니다.
.NET 개발 용어로 알려진 비동기 프로그래밍 모델 을 사용하여 명령 Begin
실행을 코드에 실행하는 "녹색 표시"를 제공하는 End
메소드 와 결과를 수집 하는 메소드로 분할 할 수 있습니다 . 이 경우 우리는 실제로 피드백에 관심이 없기 때문에 ( w32tm
어쨌든 출력을 기다리지 않습니다 ) 첫 번째 메소드를 호출하면됩니다.
$PSinstance.BeginInvoke()
RunspacePool에 싸서
위의 기술을 사용하여 새 연결을 작성하고 병렬 실행 플로우에서 원격 명령을 호출하는 순차적 반복을 랩핑 할 수 있습니다.
$ComputerNames = Get-ADComputer -filter * -Properties dnsHostName |select -Expand dnsHostName
$Code = {
param($Credentials,$ComputerName)
$session = New-PSSession -ComputerName $ComputerName -Credential $Credentials
Invoke-Command -Session $session -ScriptBlock {w32tm /resync /nowait /rediscover}
}
$creds = Get-Credential domain\user
$rsPool = [runspacefactory]::CreateRunspacePool(1,8)
$rsPool.Open()
foreach($ComputerName in $ComputerNames)
{
$PSinstance = [powershell]::Create().AddScript($Code).AddArgument($creds).AddArgument($ComputerName)
$PSinstance.RunspacePool = $rsPool
$PSinstance.BeginInvoke()
}
CPU에 8 개의 실행 영역을 한 번에 모두 실행할 수있는 용량이 있다고 가정하면 실행 시간이 크게 단축되지만 사용 된 "고급"방법으로 인해 스크립트의 가독성이 떨어짐을 알 수 있습니다.
최적의 병렬화 정도 결정 :
100 개의 실행 영역을 동시에 실행할 수있는 RunspacePool을 쉽게 만들 수 있습니다.
[runspacefactory]::CreateRunspacePool(1,100)
그러나 하루가 끝나면 로컬 CPU가 처리 할 수있는 실행 단위 수로 결정됩니다. 다시 말해, 코드가 실행되는 한 논리 프로세서가 코드 실행을 디스패치하는 것보다 더 많은 실행 영역을 허용하는 것은 의미가 없습니다.
WMI 덕분에이 임계 값을 결정하기가 매우 쉽습니다.
$NumberOfLogicalProcessor = (Get-WmiObject Win32_Processor).NumberOfLogicalProcessors
[runspacefactory]::CreateRunspacePool(1,$NumberOfLogicalProcessors)
반면에, 네트워크 대기 시간과 같은 외부 요인으로 인해 자체적으로 실행중인 코드에 대기 시간이 많이 걸리더라도 논리 프로세서보다 더 많은 동시 실행 영역을 실행하면 이점을 얻을 수 있으므로 테스트하고 싶을 것입니다 손익 분기를 찾을 수있는 가능한 최대 실행 공간 범위 :
foreach($n in ($NumberOfLogicalProcessors..($NumberOfLogicalProcessors*3)))
{
Write-Host "$n: " -NoNewLine
(Measure-Command {
$Computers = Get-ADComputer -filter * -Properties dnsHostName |select -Expand dnsHostName -First 100
...
[runspacefactory]::CreateRunspacePool(1,$n)
...
}).TotalSeconds
}