首页 文章

Powershell可以并行运行命令吗?

提问于
浏览
101

我有一个powershell脚本对一堆图像进行一些批处理,我想做一些并行处理 . Powershell似乎有一些后台处理选项,如启动作业,等待作业等,但我找到的并行工作的唯一好资源是编写脚本文本并运行它们(PowerShell Multithreading

理想情况下,我喜欢类似于.net 4中的并行foreach的东西 .

有点像:

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

也许我会更好的只是下降到c#...

5 回答

  • 75

    要完成以前的答案,您还可以使用 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
    
  • 1

    后台作业设置昂贵且不可重复使用 . PowerShell MVP Oisin Grehan有一个很好的PowerShell多线程示例http://www.nivot.org/2009/01/22/CTP3TheRunspaceFactoryAndPowerShellAccelerators.aspx

    (10/25/2010网站已关闭):

    我在这里使用了改编的Oisin脚本用于数据加载例程:

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

  • 8

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

    我创建了一个invoke-async,允许您同时运行多个脚本块/ cmdlet /函数 . 这对于小型作业(子网扫描或针对100台计算机的wmi查询)非常有用,因为创建运行空间的开销与启动作业的启动时间非常相似 . 它可以像这样使用 .

    使用scriptblock,

    $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
    

    只是cmdlet / function

    $servers = Get-Content servers.txt 
    
    $rtn = Invoke-Async -Set $servers -SetParam computername -Params @{count=1} -Cmdlet Test-Connection -ThreadCount 50
    
  • 86

    您可以使用Background Jobs在Powershell 2中执行并行作业 . 查看Start-Job和其他作业cmdlet .

    # 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
    
  • 6

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

    要将变量从父上下文传递到子上下文,请使用 Start-Job 上的 -ArgumentList 参数发送它并在脚本块内使用 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文档的参考作为支持证据,但是,唉,我的搜索没有结果 . 如果您碰巧知道上下文分离的记录,请在此发表评论以告诉我!)

相关问题