Зарегистрировать событие отслеживания для всех фоновых заданий?
Добрый день,
Я работал с попыткой зарегистрировать событие, основанное на завершении всех заданий. Я могу успешно зарегистрировать один, но мне нравится получать всплывающее сообщение после завершения всех фоновых заданий. Кто-нибудь знаком с тем, как это сделать?
Я попытался сделать следующее, но он выдает ошибку, говоря, что job is null:
1..10 | ForEach-Object -Process {
Start-Job { Start-Sleep $_ } -Name "$_" | Out-Null} -OutVariable $jobs
Register-ObjectEvent $jobs StateChanged -Action {
[System.Windows.MessageBox]::Show('Done')
$eventSubscriber | Unregister-Event
$eventSubscriber.Action | Remove-Job
} | Out-Null
Я чувствую себя
Do{}Until()
loop может это сделать, но я не уверен, как зарегистрировать это, чтобы проверять, пока работа не будет завершена. Также пытался проследить, как другие люди делали это, используя разные языки, но я не могу понять.
Я не хочу публиковать все, что я пробовал, чтобы этот пост никому не утомлял. Искал и в Google, но я не смог найти много информации о регистрации объекта для нескольких заданий.
ИЗМЕНИТЬ Вот что работает:
$job = Start-Job -Name GetLogFiles { Start-Sleep 10 }
Register-ObjectEvent $job StateChanged -Action {
[System.Windows.MessageBox]::Show('Done')
$eventSubscriber | Unregister-Event
$eventSubscriber.Action | Remove-Job
} | Out-Null
Это то, что мне нравится, но оценивать все вакансии, а не только одну.
1 ответ
Вот что лично использует при мониторинге выполняемых заданий:
$jobs= 1..10 | ForEach-Object -Process {
Start-Job { Start-Sleep $using:_ ; "job {0} done" -f $using:_ } -Name "$_"
}
do{
$i = (Get-Job -State Completed).count
$progress = @{
Activity = 'Jobs completed'
Status = "$i of {0}" -f $jobs.Count
PercentComplete = $i / $jobs.count * 100
}
Write-Progress @progress
Start-Sleep -Milliseconds 10
}
until($i -eq $jobs.Count)
$result = Get-Job | Receive-Job
$jobs | Remove-Job
Конечно, при определенных сценариях, когда я знаю, что некоторые задания могут потерпеть неудачу, я меняю
until(...)
условие для чего-то другого и
do {...}
содержит логику перезапуска невыполненных заданий.
Изменить 1:
Стоит отметить, что
Start-Job
не стоит вашего времени, если вас интересует многопоточность, она оказалась медленнее, чем линейный цикл во многих сценариях. Вы должны смотреть наThreadJob Module
Изменить 2:
После некоторого тестирования это сработало для меня:
# Clear the Event queue
Get-EventSubscriber|Unregister-Event
# Clear the Job queue
Get-Job|Remove-Job
1..10 | ForEach-Object -Process {
$job = Start-Job { Sleep -Seconds (1..20|Get-Random) } -Name "$_"
Register-ObjectEvent -InputObject $job -EventName StateChanged -Action {
$eventSubscriber | Unregister-Event
$eventSubscriber.Action | Remove-Job
if(-not (Get-EventSubscriber))
{
[System.Windows.MessageBox]::Show('Done')
}
} | Out-Null
}
Сначала я даже не знал, что это возможно, поэтому спасибо за указание на это. Отличный вопрос :)