[英]Powershell Throttle Multi thread jobs via job completion
我发现的所有内容都使用预定义的睡眠时间来限制工作。 我需要油门等到工作完成后再开始新工作。 一次只能运行4个作业。
因此脚本将运行4并且当前暂停10秒然后运行其余部分。 我想要的是脚本只允许一次运行4个作业,并且当作业完成时,新的作业将被启动。
通过服务器名称列表初始化作业。
是否可以存档?
$servers = Get-Content "C:\temp\flashfilestore\serverlist.txt"
$scriptBlock = { #DO STUFF }
$MaxThreads = 4
foreach($server in $servers) {
Start-Job -ScriptBlock $scriptBlock -argumentlist $server
While($(Get-Job -State 'Running').Count -ge $MaxThreads) {
sleep 10 #Need this to wait until a job is complete and kick off a new one.
}
}
Get-Job | Wait-Job | Receive-Job
您可以测试以下内容:
$servers = Get-Content "C:\temp\flashfilestore\serverlist.txt"
$scriptBlock = { #DO STUFF }
invoke-command -computerName $servers -scriptblock $scriptBlock -jobname 'YourJobSpecificName' -throttlelimit 4 -AsJob
此命令使用Invoke-Command cmdlet及其AsJob参数来启动在多台计算机上运行scriptblock的后台作业。 由于该命令不能同时运行4次以上,因此该命令使用Invoke-Command的ThrottleLimit参数将并发命令数限制为4。
请注意该文件包含域中的计算机名称。
为了避免发明轮子,我建议使用现有工具之一。
其中一个是脚本Invoke-Parallel.ps1 。 它是用PowerShell编写的,你可以看到它是如何直接实现的。 它很容易获得,它不需要任何安装使用它。
另一个是SplitPipeline模块。 它可能更快,因为它是用C#编写的。 它还涵盖了一些更多的用例,例如慢速或无限输入,初始化和清理脚本的使用。
在后一种情况下,具有4个并行流水线的代码将是
$servers | Split-Pipeline -Count 4 {process{ <# DO STUFF on $_ #> }}
我写了一篇博客文章,通过实际线程涵盖了任何给定脚本的多线程。 你可以在这里找到完整的帖子:
http://www.get-blog.com/?p=189
基本设置是:
$ISS = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $ISS, $Host)
$RunspacePool.Open()
$Code = [ScriptBlock]::Create($(Get-Content $FileName))
$PowershellThread = [powershell]::Create().AddScript($Code)
$PowershellThread.RunspacePool = $RunspacePool
$Handle = $PowershellThread.BeginInvoke()
$Job = "" | Select-Object Handle, Thread, object
$Job.Handle = $Handle
$Job.Thread = $PowershellThread
$Job.Object = $Object.ToString()
$Job.Thread.EndInvoke($Job.Handle)
$Job.Thread.Dispose()
而不是sleep 10
你也可以等待工作( -any
工作):
Get-Job | Wait-Job -Any | Out-Null
当没有更多工作要开始时,开始打印输出。 您也可以在上述命令后立即在循环内执行此操作。 该脚本将在完成后接收作业,而不是等到结束。
Get-Job -State Completed | % {
Receive-Job $_ -AutoRemoveJob -Wait
}
所以你的脚本看起来像这样:
$servers = Get-Content "C:\temp\flashfilestore\serverlist.txt"
$scriptBlock = { #DO STUFF }
$MaxThreads = 4
foreach ($server in $servers) {
Start-Job -ScriptBlock $scriptBlock -argumentlist $server
While($(Get-Job -State Running).Count -ge $MaxThreads) {
Get-Job | Wait-Job -Any | Out-Null
}
Get-Job -State Completed | % {
Receive-Job $_ -AutoRemoveJob -Wait
}
}
While ($(Get-Job -State Running).Count -gt 0) {
Get-Job | Wait-Job -Any | Out-Null
}
Get-Job -State Completed | % {
Receive-Job $_ -AutoRemoveJob -Wait
}
说了这么多,如果你可以使用它们,我更喜欢运行空间(类似于Ryans帖子)甚至是工作流程。 这些资源比开始多个PowerShell流程要少得多。
你的脚本看起来很好,尝试添加类似的东西
Write-Host ("current count:" + ($(Get-Job -State 'Running').Count) + " on server:" + $server)
在你的while循环之后,确定作业数量是否会下降到你不期望的地方。
我注意到每个Start-Job命令都在任务管理器中导致了一个额外的conhost.exe
进程。 知道这一点,我能够使用以下逻辑进行限制,其中5
是我所需的并发线程数(因此我在-gt
语句中使用4
,因为我正在寻找大于的数量):
while((Get-Process conhost -ErrorAction SilentlyContinue).Count -gt 4){Start-Sleep -Seconds 1}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.