我尝试使用PowerShell并行处理文件,同时限制当前正在执行的进程数。如果要处理的文件列表在执行开始时已知,则可以使用queue来实现此目的。
但是,此脚本需要容纳添加到"处理"的文件。脚本运行时的目录。我尝试实现这一目标的方法是让每个作业在完成后自行删除,然后调用检查文件的函数来处理/启动新作业。
我遇到的困难是让PowerShell在退出前等待处理完成。
使用Get-Job | Wait-Job
似乎会导致阻止。也就是说,除非我手动干预,否则脚本永远不会返回。在ISE中,在处理$maxConcurrentJobs
个文件后,我必须按Ctrl + C才能处理其余文件并允许脚本退出。
在PowerShell ISE中使用while循环可以正常工作。但是,在PowerShell(命令行)中,while循环方法只处理$maxConcurrentJobs
个文件数 - 即"中的任何其他文件来处理"永远不会得到处理显然,当第一组处理作业完成时,下一组不会启动。
While ($true) {
if ((Get-Job | Where-Object { $_.PSJobTypeName -eq 'BackgroundJob' }).Count -eq 0) { break; }
Start-Sleep -s 1
}
如何在没有脚本阻止或过早退出的情况下等待我的所有脚本作业完成?
function StartProcessingFile([IO.FileInfo]$file) {
$destination = "$PSScriptRoot\Processed\$((get-date).ToString('yyyyMMdd-HHmmss'))-$($file.BaseName).csv"
$inputFile = Move-Item $file.FullName -Destination $destination -PassThru
Start-Job -Name $file.Name -ScriptBlock { param($x) Start-Sleep -s 10; } -ArgumentList $inputFile # In real life, ScriptBlock will call a PowerShell cmdlet that processes the file
}
$maxConcurrentJobs = 2;
function ProcessFiles {
While ((Get-Job | Where-Object { $_.PSJobTypeName -eq 'BackgroundJob' }).Count -lt $maxConcurrentJobs) {
$file = Get-ChildItem -Path "$PSScriptRoot\ToProcess" *.csv | Sort-Object -Property LastWriteTime | Select-Object -First 1
if ($file -eq $null) { break }
$job = StartProcessingFile($file)
Register-ObjectEvent -InputObject $job -EventName StateChanged -Action { Unregister-Event $eventsubscriber.SourceIdentifier; Remove-Job $eventsubscriber.SourceIdentifier; Remove-Job $eventsubscriber.SourceObject; ProcessFiles; } | Out-Null
}
}
ProcessFiles
While ($true) {
Get-Job
Write-Host
if ((Get-Job | Where-Object { $_.PSJobTypeName -eq 'BackgroundJob' }).Count -eq 0) { break; }
Start-Sleep -s 1
}
#Get-Job | Wait-Job