Зарегистрировать событие отслеживания для всех фоновых заданий?

Добрый день,

Я работал с попыткой зарегистрировать событие, основанное на завершении всех заданий. Я могу успешно зарегистрировать один, но мне нравится получать всплывающее сообщение после завершения всех фоновых заданий. Кто-нибудь знаком с тем, как это сделать?

Я попытался сделать следующее, но он выдает ошибку, говоря, что 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
}

Сначала я даже не знал, что это возможно, поэтому спасибо за указание на это. Отличный вопрос :)

Другие вопросы по тегам