Güncelleme - Bu cevap, PowerShell çalışma alanlarının sürecini ve mekaniğini ve bunların ardışık olmayan iş yüklerini size nasıl bağlamanıza yardımcı olabileceğini açıklasa da, PowerShell meraklısı Warren 'Cookie Monster' F daha fazla mil kullandı ve bu aynı kavramları tek bir araca dahil etti. çağırdı - aşağıda açıkladığım şeyi yapıyor ve o zamandan beri, giriş modülleri dahil olmak üzere oturum açma ve hazırlık oturumu için isteğe bağlı anahtarlarla genişleten, gerçekten harika şeyler - kendi parlak çözümünüzü oluşturmadan önce kontrol etmenizi şiddetle tavsiye ediyorum !Invoke-Parallel
Paralel Runspace yürütme ile:
Kaçınılmaz bekleme süresini azaltmak
Özgün özel durumda, çalıştırılabilir çalıştırılan dosya /nowait
, iş (bu durumda, zaman senkronizasyonu) kendi başına bittiğinde, başlatılan iş parçacığının engellenmesini önleyen bir seçeneğe sahiptir.
Bu, genel yürütme süresini, ihraç edenin bakış açısıyla büyük ölçüde azaltır, ancak her bir makineye bağlantı hala sıralı olarak yapılır. Binlerce müşteriye sırayla bağlanmak, zaman aşımı beklemelerinin birikmesi nedeniyle bir nedenden veya erişilemeyen makinelerin sayısına bağlı olarak uzun sürebilir.
Bir veya birkaç ardışık zaman aşımı durumunda, sonraki tüm bağlantıları sıraya koymak zorunda kalmamak için, paralel olarak yürütülen PowerShell Çalışma Alanlarını ayırmak için komutları bağlama ve çağırma işini gönderebiliriz.
Runspace nedir?
Bir Runspace sanal kap içinde Powershell kod yürütür ve temsil / a PowerShell açıklamada / komuta perspektifinden Çevre tutar.
Genel olarak, 1 Runspace = 1 yürütme iş parçacığı, bu nedenle PowerShell betiğimizi "multi-thread" yapmamız gereken tek şey, daha sonra paralel olarak çalışabilen Runspaces koleksiyonudur.
Orijinal sorun gibi, komutları çalıştırma işi birden fazla çalışma alanı olarak ayrılabilir:
- RunspacePool oluşturma
- RunspacePool'a bir PowerShell betiği veya eşdeğer bir çalıştırılabilir kod parçası atama
- Kodu eşzamansız olarak çağırın (yani, kodun geri dönmesini beklemeniz gerekmez)
RunspacePool şablonu
PowerShell, [RunspaceFactory]
çalışma alanı bileşenlerinin oluşturulmasında bize yardımcı olacak bir tür hızlandırıcıya sahiptir - hadi işe koyulalım
1. Bir RunspacePool oluşturun ve Open()
bu:
$RunspacePool = [runspacefactory]::CreateRunspacePool(1,8)
$RunspacePool.Open()
İki argüman geçirilen CreateRunspacePool()
, 1
ve 8
bize etkili vererek minimum ve herhangi bir zamanda çalıştırmak için izin runspaces maksimum sayıda olan maksimum paralellik derecesi 8.
2. PowerShell örneği oluşturun, çalıştırılabilir bir kod ekleyin ve RunspacePool'umuza atayın:
PowerShell örneği, powershell.exe
işlemle aynı değildir (bu gerçekten bir Host uygulamasıdır), ancak yürütülecek PowerShell kodunu temsil eden bir dahili çalışma zamanı nesnesidir. [powershell]
PowerShell içinde yeni bir PowerShell örneği oluşturmak için tür hızlandırıcıyı kullanabiliriz :
$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. PowerShell örneğini APM kullanarak eşzamansız olarak çağırın:
.NET geliştirme terminolojisinde Asenkron Programlama Modeli olarak bilinenleri kullanarak , komutun Begin
çalıştırılmasına "yeşil ışık" verilmesi için bir yöntemin çağrılmasını End
ve sonuçları toplama yöntemini bölebiliriz . Bu durumda herhangi bir geri bildirim ile gerçekten ilgilenmediğimizden (herhangi bir zamanda çıktının w32tm
çıkmasını beklemiyoruz ), yalnızca ilk yöntemi çağırarak yapabiliriz.
$PSinstance.BeginInvoke()
Bir RunspacePool içinde sarma
Yukarıdaki tekniği kullanarak, yeni bağlantılar oluşturma ve uzak komutunu paralel yürütme akışına çağırarak art arda yinelemelerini sarabiliriz:
$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'nun 8 çalışma alanının tümünü aynı anda yürütme kapasitesine sahip olduğunu varsayarak, yürütme süresinin büyük ölçüde azaldığını, ancak kullanılan "gelişmiş" yöntemlerden dolayı komut dosyasının okunabilirliği pahasına olduğunu görmemiz gerekir.
Optimum paralellik derecesinin belirlenmesi:
Aynı anda 100 çalışma alanının yürütülmesine izin veren bir RunspacePool oluşturabiliriz:
[runspacefactory]::CreateRunspacePool(1,100)
Ancak günün sonunda, yerel CPU'muzun kaç tane yürütme birimi işleyebileceğine bağlı. Başka bir deyişle, kodunuz yürütüldüğü sürece, kod yürütmesini gönderecek mantıksal işlemcilere sahip olduğunuzdan daha fazla çalışma alanına izin vermek mantıklı değildir.
WMI sayesinde, bu eşiğin belirlenmesi oldukça kolaydır:
$NumberOfLogicalProcessor = (Get-WmiObject Win32_Processor).NumberOfLogicalProcessors
[runspacefactory]::CreateRunspacePool(1,$NumberOfLogicalProcessors)
Öte yandan, yürütmekte olduğunuz kod, ağ gecikmesi gibi dış etkenler nedeniyle çok fazla bekleme süresi içeriyorsa, mantıksal işlemcilere sahip olduğunuzdan daha fazla eşzamanlı çalışma alanı çalıştırmanın avantajlarından yararlanabilirsiniz. sonu bulmak için mümkün olan maksimum çalışma alanı aralığı :
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
}