Çoklu iş parçacığı kullanılırken ilerleme durumu görüntüleniyor
PowerShell 7.0'dan başlayarak, birden fazla iş parçacığında aynı anda çalışabilme yeteneği, Foreach-Object cmdlet'indeki Parallel parametresi kullanılarak mümkündür. Ancak bu iş parçacıklarının ilerlemesini izlemek zor olabilir. Normalde, Yazma İlerlemesini kullanarak bir işlemin ilerlemesini izleyebilirsiniz. Ancak PowerShell, Paralel kullanırken her iş parçacığı için ayrı bir çalışma alanı kullandığından, ilerlemeyi ana bilgisayara geri bildirmek, Yazma İlerlemesi'nin normal kullanımı kadar kolay değildir.
İlerlemeyi izlemek için senkronize edilmiş karma tablo kullanma
Birden çok iş parçacığından ilerleme yazarken izleme zorlaşır çünkü PowerShell'de paralel işlemler çalıştırıldığında her işlemin kendi çalışma alanı vardır. Bunu aşmak için senkronize bir hashtable kullanabilirsiniz. Senkronize edilmiş karma tablo, birden fazla iş parçacığı tarafından aynı anda hata vermeden değiştirilebilen, iş parçacığı açısından güvenli bir veri yapısıdır.
Kurmak
Bu yaklaşımın dezavantajlarından biri, her şeyin hatasız çalışmasını sağlamak için biraz karmaşık bir kurulum gerektirmesidir.
$dataset = @(
@{
Id = 1
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 2
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 3
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 4
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 5
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
)
# Create a hashtable for process.
# Keys should be ID's of the processes
$origin = @{}
$dataset | Foreach-Object {$origin.($_.id) = @{}}
# Create synced hashtable
$sync = [System.Collections.Hashtable]::Synchronized($origin)
Bu bölüm, üç farklı amaç için üç farklı veri yapısı oluşturur.
$dataSet değişkeni, değiştirilme riski olmadan sonraki adımları koordine etmek için kullanılan bir karma tablo dizisini saklar. Koleksiyonda yineleme sırasında bir nesne koleksiyonu değiştirilirse PowerShell bir hata atar. Döngüdeki nesne koleksiyonunu, değiştirilen nesnelerden ayrı tutmalısınız. Her karma tablosundaki Id anahtarı, sahte bir sürecin tanımlayıcısıdır. Bekle tuşu, izlenen her sahte sürecin iş yükünü simüle eder.
$origin değişkeni, her anahtarın sahte işlem kimliklerinden biri olduğu iç içe geçmiş bir hash tablosunu saklar. Daha sonra $sync değişkeninde saklanan senkronize karma tabloyu nemlendirmek için kullanılır. $sync değişkeni, ilerlemeyi görüntüleyen üst çalışma alanına geri bildirimde bulunmaktan sorumludur.
Süreçleri çalıştırmak
Bu bölüm çok iş parçacıklı işlemleri çalıştırır ve ilerlemeyi görüntülemek için kullanılan çıktıların bir kısmını oluşturur.
$job = $dataset | Foreach-Object -ThrottleLimit 3 -AsJob -Parallel {
$syncCopy = $using:sync
$process = $syncCopy.$($PSItem.Id)
$process.Id = $PSItem.Id
$process.Activity = "Id $($PSItem.Id) starting"
$process.Status = "Processing"
# Fake workload start up that takes x amount of time to complete
start-sleep -Milliseconds ($PSItem.wait*5)
# Process. update activity
$process.Activity = "Id $($PSItem.id) processing"
foreach ($percent in 1..100)
{
# Update process on status
$process.Status = "Handling $percent/100"
$process.PercentComplete = (($percent / 100) * 100)
# Fake workload that takes x amount of time to complete
Start-Sleep -Milliseconds $PSItem.Wait
}
# Mark process as completed
$process.Completed = $true
}
Sahte işlemler Foreach-Object'e gönderilir ve iş olarak başlatılır. Bir kuyrukta birden fazla işlemin çalıştırıldığını vurgulamak için ThrottleLimit 3 olarak ayarlanmıştır. İşler $job değişkeninde saklanır ve daha sonra tüm süreçlerin ne zaman bittiğini bilmemizi sağlar.
PowerShell'de bir üst kapsam değişkenine başvurmak için using: ifadesini kullanırken, onu dinamik hale getirmek için ifadeler kullanamazsınız. Örneğin, $process değişkenini şu şekilde oluşturmaya çalışırsanız, $process=$using:sync.$ ($PSItem.id), şunu elde edersiniz: orada ifadeleri kullanamayacağınızı belirten bir hata. Bu nedenle, $sync değişkenine başarısız olma riski olmadan referans verebilmek ve değiştirebilmek için $syncCopy değişkenini oluşturuyoruz.
Daha sonra, senkronize karma tablosu anahtarlarına atıfta bulunarak $process değişkenini kullanarak o anda döngüde olan sürecin ilerlemesini temsil eden bir karma tablosu oluştururuz. Etkinlik ve Durum tuşları, sonraki bölümde belirli bir sahte işlemin durumunu görüntülemek için Yazma İlerlemesi için parametre değerleri olarak kullanılır.
foreach döngüsü yalnızca sürecin çalışmasını simüle etmenin bir yoludur ve Start-'ı ayarlamak için . Sürecinizin ilerleyişini nasıl hesapladığınız farklılık gösterebilir.$dataSet Wait özelliğine göre rastgele seçilir. Milisaniye kullanarak uyku
Birden fazla işlemin ilerlemesini görüntüleme
Artık sahte süreçler iş olarak çalıştığına göre süreçlerin ilerlemesini PowerShell penceresine yazmaya başlayabiliriz.
while($job.State -eq 'Running')
{
$sync.Keys | Foreach-Object {
# If key is not defined, ignore
if(![string]::IsNullOrEmpty($sync.$_.keys))
{
# Create parameter hashtable to splat
$param = $sync.$_
# Execute Write-Progress
Write-Progress @param
}
}
# Wait to refresh to not overload gui
Start-Sleep -Seconds 0.1
}
$job değişkeni ana job'u içerir ve sahte süreçlerin her biri için bir alt job'a sahiptir. Alt işlerden herhangi biri hâlâ çalışıyorken ana iş Durumu "Çalışıyor" olarak kalacaktır. Bu, tüm işlemler bitene kadar her işlemin ilerleyişini sürekli olarak güncellemek için while döngüsünü kullanmamıza olanak tanır.
While döngüsü içinde $sync değişkenindeki tuşların her biri arasında döngü yaparız. Bu senkronize bir karma tablo olduğundan sürekli güncellenir ancak yine de herhangi bir hata vermeden erişilebilir.
Raporlanan işlemin gerçekten IsNullOrEmpty() yöntemini kullanarak çalıştığından emin olmak için bir kontrol vardır. Süreç başlatılmamışsa döngü bu konuda rapor vermez ve başlatılan sürece ulaşana kadar bir sonrakine geçer. İşlem başlatılırsa, geçerli anahtardaki hash tablosu, parametreleri Yazma İlerlemesi'ne aktarmak için kullanılır.
Tam örnek
# Example workload
$dataset = @(
@{
Id = 1
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 2
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 3
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 4
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 5
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
)
# Create a hashtable for process.
# Keys should be ID's of the processes
$origin = @{}
$dataset | Foreach-Object {$origin.($_.id) = @{}}
# Create synced hashtable
$sync = [System.Collections.Hashtable]::Synchronized($origin)
$job = $dataset | Foreach-Object -ThrottleLimit 3 -AsJob -Parallel {
$syncCopy = $using:sync
$process = $syncCopy.$($PSItem.Id)
$process.Id = $PSItem.Id
$process.Activity = "Id $($PSItem.Id) starting"
$process.Status = "Processing"
# Fake workload start up that takes x amount of time to complete
start-sleep -Milliseconds ($PSItem.wait*5)
# Process. update activity
$process.Activity = "Id $($PSItem.id) processing"
foreach ($percent in 1..100)
{
# Update process on status
$process.Status = "Handling $percent/100"
$process.PercentComplete = (($percent / 100) * 100)
# Fake workload that takes x amount of time to complete
Start-Sleep -Milliseconds $PSItem.Wait
}
# Mark process as completed
$process.Completed = $true
}
while($job.State -eq 'Running')
{
$sync.Keys | Foreach-Object {
# If key is not defined, ignore
if(![string]::IsNullOrEmpty($sync.$_.keys))
{
# Create parameter hashtable to splat
$param = $sync.$_
# Execute Write-Progress
Write-Progress @param
}
}
# Wait to refresh to not overload gui
Start-Sleep -Seconds 0.1
}