繁体   English   中英

Powershell Throttle通过作业完成多线程作业

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM