【问题标题】:Powershell Throttle Multi thread jobs via job completion通过作业完成的 Powershell Throttle 多线程作业
【发布时间】:2014-02-26 12:14:47
【问题描述】:

我发现的所有 tuts 都使用预定义的睡眠时间来限制工作。 我需要油门等到工作完成后再开始新的工作。 一次只能运行 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

【问题讨论】:

    标签: multithreading powershell throttling


    【解决方案1】:

    您可以测试以下内容:

    $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 参数来启动在多台计算机上运行脚本块的后台作业。因为命令并发运行次数不能超过4次,所以命令使用Invoke-Command的ThrottleLimit参数来限制并发命令数为4。

    请注意该文件包含域中的计算机名称。

    【讨论】:

      【解决方案2】:

      为了避免发明轮子,我建议使用其中一个 现有工具。

      其中之一是脚本 Invoke-Parallel.ps1。 它是用PowerShell编写的,你可以直接看到它是如何实现的。它是 易于获取,无需任何安装即可使用。

      另一个是模块SplitPipeline。 它可能工作得更快,因为它是用 C# 编写的。它还涵盖了更多用途 情况,例如缓慢或无限输入、使用初始化和清理脚本。

      在后一种情况下,具有 4 个并行管道的代码将是

      $servers | Split-Pipeline -Count 4 {process{ <# DO STUFF on $_ #> }}
      

      【讨论】:

        【解决方案3】:

        您的脚本看起来不错,尝试添加类似

        的内容

        Write-Host ("current count:" + ($(Get-Job -State 'Running').Count) + " on server:" + $server)

        在您的 while 循环之后确定作业计数是否在您不期望的地方下降。

        【讨论】:

          【解决方案4】:

          我写了一篇博客文章,其中介绍了通过实际线程对任何给定脚本进行多线程处理。你可以在这里找到完整的帖子:

          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()
          

          【讨论】:

          • 不错的链接。我也更喜欢运行空间,因为它们占用的资源较少。
          • 嗨 Ryan,你的博客还在吗?此 URL 不再解析 :(
          【解决方案5】:

          除了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 进程相比,这些资源占用的资源要少得多。

          【讨论】:

            【解决方案6】:

            我注意到每个 Start-Job 命令都会在任务管理器中产生一个额外的conhost.exe 进程。知道了这一点,我能够使用以下逻辑进行节流,其中5 是我想要的并发线程数(所以我在-gt 语句中使用4,因为我正在寻找大于的计数):

            while((Get-Process conhost -ErrorAction SilentlyContinue).Count -gt 4){Start-Sleep -Seconds 1}
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-01-20
              • 2013-01-19
              • 1970-01-01
              • 1970-01-01
              • 2019-09-06
              • 1970-01-01
              • 1970-01-01
              • 2012-04-02
              相关资源
              最近更新 更多