代码之家  ›  专栏  ›  技术社区  ›  Alan Jackson

Powershell可以并行运行命令吗?

  •  105
  • Alan Jackson  · 技术社区  · 14 年前

    PowerShell Multithreading )

    理想情况下,我希望类似于.net 4中的并行foreach。

    一些看起来很无趣的东西,比如:

    foreach-parallel -threads 4 ($file in (Get-ChildItem $dir))
    {
       .. Do Work
    }
    

    也许我最好直接去c#。。。

    5 回复  |  直到 14 年前
        1
  •  95
  •   Nino Filiu    6 年前

    可以使用 Background Jobs . 退房 Start-Job

    # Loop through the server list
    Get-Content "ServerList.txt" | %{
    
      # Define what each job does
      $ScriptBlock = {
        param($pipelinePassIn) 
        Test-Path "\\$pipelinePassIn\c`$\Something"
        Start-Sleep 60
      }
    
      # Execute the jobs in parallel
      Start-Job $ScriptBlock -ArgumentList $_
    }
    
    Get-Job
    
    # Wait for it all to complete
    While (Get-Job -State "Running")
    {
      Start-Sleep 10
    }
    
    # Getting the information back from the jobs
    Get-Job | Receive-Job
    
        2
  •  94
  •   Michael Sorens    13 年前

    史蒂夫·汤森的回答在理论上是正确的,但在实践中却并非如@likwid所指出的那样。我修改后的代码考虑了 工作环境障碍 --默认情况下没有任何东西能越过这个障碍!自动档 $_ 因此,变量可以在循环中使用,但不能直接在脚本块中使用,因为它位于作业创建的单独上下文中。

    若要将变量从父上下文传递到子上下文,请使用 -ArgumentList Start-Job 发送并使用 param 在脚本块中接收它。

    cls
    # Send in two root directory names, one that exists and one that does not.
    # Should then get a "True" and a "False" result out the end.
    "temp", "foo" | %{
    
      $ScriptBlock = {
        # accept the loop variable across the job-context barrier
        param($name) 
        # Show the loop variable has made it through!
        Write-Host "[processing '$name' inside the job]"
        # Execute a command
        Test-Path "\$name"
        # Just wait for a bit...
        Start-Sleep 5
      }
    
      # Show the loop variable here is correct
      Write-Host "processing $_..."
    
      # pass the loop variable across the job-context barrier
      Start-Job $ScriptBlock -ArgumentList $_
    }
    
    # Wait for all to complete
    While (Get-Job -State "Running") { Start-Sleep 2 }
    
    # Display output from all jobs
    Get-Job | Receive-Job
    
    # Cleanup
    Remove-Job *
    

    (我通常喜欢提供PowerShell文档的参考作为支持证据,但是,唉,我的搜索没有结果。如果你碰巧知道在哪里记录了上下文分离,请在这里发表评论让我知道!)

        3
  •  8
  •   jrich523    11 年前

    http://gallery.technet.microsoft.com/scriptcenter/Invoke-Async-Allows-you-to-83b0c9f0

    有了脚本块,

    $sb = [scriptblock] {param($system) gwmi win32_operatingsystem -ComputerName $system | select csname,caption} 
    
    $servers = Get-Content servers.txt 
    
    $rtn = Invoke-Async -Set $server -SetParam system  -ScriptBlock $sb
    

    只是命令/函数

    $servers = Get-Content servers.txt 
    
    $rtn = Invoke-Async -Set $servers -SetParam computername -Params @{count=1} -Cmdlet Test-Connection -ThreadCount 50
    
        4
  •  7
  •   jpaugh JotaBe    5 年前

    背景作业的设置成本很高,而且不可重用。PowerShell MVP欧辛格雷汉 有 a good example

    (2010年10月25日网站关闭,但可通过网络档案访问)。

    我在这里使用了用于数据加载例程的自适应Oisin脚本:

    http://rsdd.codeplex.com/SourceControl/changeset/view/a6cd657ea2be#Invoke-RSDDThreaded.ps1

        5
  •  7
  •   js2010    5 年前

    1. 作业(或PS 6/7或模块中的线程作业)
    2. 启动进程
    3. 工作流程
    4. 对多台计算机调用命令,这些计算机都可以是本地主机(必须是管理员)
    5. Powershell 7有一个 foreach-object -parallel

    这里的工作流实际上是一个foreach-parallel:

    workflow work {
      foreach -parallel ($i in 1..3) { 
        sleep 5 
        "$i done" 
      }
    }
    
    work
    
    3 done
    1 done
    2 done
    

    或具有并行块的工作流:

    function sleepfor($time) { sleep $time; "sleepfor $time done"}
    
    workflow work {
      parallel {
        sleepfor 3
        sleepfor 2
        sleepfor 1
      }
      'hi'
    }
    
    work 
    
    sleepfor 1 done
    sleepfor 2 done
    sleepfor 3 done
    hi
    

    下面是一个带有runspaces示例的api:

    $a =  [PowerShell]::Create().AddScript{sleep 5;'a done'}
    $b =  [PowerShell]::Create().AddScript{sleep 5;'b done'}
    $c =  [PowerShell]::Create().AddScript{sleep 5;'c done'}
    $r1,$r2,$r3 = ($a,$b,$c).begininvoke() # run in background
    $a.EndInvoke($r1); $b.EndInvoke($r2); $c.EndInvoke($r3) # wait
    ($a,$b,$c).streams.error # check for errors
    ($a,$b,$c).dispose() # clean
    
    a done
    b done
    c done
    
        6
  •  3
  •   Thomas    6 年前

    Wait-Job 要等待所有作业完成,请执行以下操作:

    For ($i=1; $i -le 3; $i++) {
        $ScriptBlock = {
            Param (
                [string] [Parameter(Mandatory=$true)] $increment
            )
    
            Write-Host $increment
        }
    
        Start-Job $ScriptBlock -ArgumentList $i
    }
    
    Get-Job | Wait-Job | Receive-Job