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

时间:2014-02-03 05:10:50

标签: multithreading powershell throttling

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

6 个答案:

答案 0 :(得分:4)

您可以测试以下内容:

$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。

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

答案 1 :(得分:4)

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

其中一个是脚本 Invoke-Parallel.ps1。 它是用PowerShell编写的,你可以看到它是如何直接实现的。它是 容易获得,并且不需要任何安装即可使用它。

另一个是模块SplitPipeline。 它可能更快,因为它是用C#编写的。它还包括更多用途 例如,缓慢或无限输入,使用初始化和清理脚本。

在后一种情况下,具有4个并行流水线的代码将是

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

而不是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流程要少得多。

答案 4 :(得分:0)

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

的内容

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

在你的while循环之后

计算出你的工作量是否会下降到你不期望的地方。

答案 5 :(得分:0)

我注意到每个Start-Job命令都在任务管理器中导致了一个额外的 public void addSeller(Seller seller){ HashMap<String,Seller> map= new HashMap<>() ; String email = seller.getEmail().replace(".",","); map.put(email,seler); database.child("sellers").setValue(map); } 进程。知道这一点,我能够使用以下逻辑进行限制,其中conhost.exe是我所需的并发线程数(因此我在5语句中使用4,因为我正在寻找一个计数大于):

-gt