且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

管道中的cmdlet是否并行执行?

更新时间:2021-07-24 22:00:27

不错,但根本不是真的.

那是什么意思?首先,让我们解决您的文档问题.以下摘录自 PowerShell 3.0版语言规范:

如果命令写入单个对象,则其后继对象将收到该对象 对象,然后在将其自己的对象写入其对象后终止 接班人.但是,如果命令写入多个对象,则 一次向后继命令传递一个,该命令执行一次 每个对象.此行为称为流传输.在流处理中, 对象一经成为对象,便会沿管道写入 可用,而不是在整个收藏集制作完成之后.

If a command writes a single object, its successor receives that object and then terminates after writing its own object(s) to its successor. If, however, a command writes multiple objects, they are delivered one at a time to the successor command, which executes once per object. This behavior is called streaming. In stream processing, objects are written along the pipeline as soon as they become available, not when the entire collection has been produced.

在处理集合时,可以这样编写命令: 可以在初始元素之前和之后进行特殊处理 最后一个元素.

When processing a collection, a command can be written such that it can do special processing before the initial element and after the final element.

现在,让我们简要了解一下 cmdlet 的组成.

Now, let's have a brief look at what a cmdlet consists of.

将cmdlet视为另一个功能可能是很诱人的,它是在每次调用时将同步执行的一组顺序语句.但是,这是不正确的.

It may be enticing to think of a cmdlet as just another function, a sequential set of statements to be executed synchronously whenever invoked. This is not correct, however.

PowerShell中的 cmdlet 是实现至少3种方法之一的对象:

A cmdlet, in PowerShell, is an object that implements one of at least 3 methods:

  • BeginProcessing() - run once, when the pipeline starts executing
  • ProcessRecord() - run for every pipeline item received
  • EndProcessing() - run once, after the last pipeline item has been processed

一旦管道开始执行,就会在管道中的每个cmdlet上调用BeginProcessing().从这个意义上说,管道中的所有cmdlet都是并行"运行的-但这种设计基本上允许我们使用单个线程来执行管道-因此,涉及多个线程的实际并行处理不必 即可执行按照设计的管道.

Once a pipeline starts executing, BeginProcessing() is called on every single cmdlet in the pipeline. In this sense, all cmdlets in the pipeline are running "in parallel" - but this design basically allows us to execute the pipeline with a single thread - so actual parallel processing involving multiple threads is not necessary to execute the pipeline as designed.

指出cmdlet在管道中同时执行 可能更准确.

It's probably more accurate to point out that cmdlets execute concurrently in a pipeline.

由于上述三种方法直接映射到我们可以在高级函数中定义的beginprocessend块,因此很容易看到此执行流程的效果.

Since the three methods above maps directly onto the begin, process and end blocks that we can define in an advanced function, it's easy to see the effect of this execution flow.

让我们尝试将5个对象馈送到由三个cmdlet组成的管道中,并使用Write-Host报告它们的状态,看看会发生什么(请参见下面的代码):

Let's try and feed 5 objects to a pipeline consisting of three cmdlets reporting their state with Write-Host and see what happens (see code below):

PS C:\> 1..5 |first |second |third |Out-Null

请注意,PowerShell通过-OutBuffer公用参数支持外部输出缓冲控制,这也会影响执行流程:

Be aware that PowerShell supports external output buffering control via the -OutBuffer common parameter, and this will influence the execution flow as well:

希望这很有道理!

这是我为上面的演示编写的代码.

Here's the code I wrote for the demonstration above.

以下函数的Write-Host输出将根据我们使用的别名来更改其颜色,因此在shell中进行区分要容易一些.

The Write-Host output from the below function will change its colour based on which alias we use, so it's a little easier to distinguish in the shell.

function Test-Pipeline {
  param(
    [Parameter(ValueFromPipeline)]
    [psobject[]]$InputObject
  )

  begin {
    $WHSplat = @{
      ForegroundColor = switch($MyInvocation.InvocationName){
        'first' {
          'Green'
        }
        'second' {
          'Yellow'
        }
        'third' {
          'Red'
        }
      }
    }
    Write-Host "Begin $($MyInvocation.InvocationName)" @WHSplat
    $ObjectCount = 0
  }

  process {
    foreach($Object in $InputObject) {
      $ObjectCount += 1
      Write-Host "Processing object #$($ObjectCount) in $($MyInvocation.InvocationName)" @WHSplat
      Write-Output $Object
    }
  }

  end {
    Write-Host "End $($MyInvocation.InvocationName)" @WHSplat
  }

}

Set-Alias -Name first  -Value Test-Pipeline
Set-Alias -Name second -Value Test-Pipeline
Set-Alias -Name third  -Value Test-Pipeline