管道中的 cmdlet 是否并行执行?
Are the cmdlets in a pipeline executing in parallel?
我在 "PowerShell Notes for professionals" 白皮书中发现了一个有趣的陈述 - "In a pipeline series each function runs parallel to the others, like parallel threads":
对吗? if "yes",是否有支持该说法的技术文档?
有点对,但完全不是真的。
这是什么意思?首先,让我们解决您的文档问题。以下内容来自 PowerShell version 3.0 Language Specification 的第 3.13 段:
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 的组成。
Cmdlet 及其构建块
将 cmdlet 视为另一个函数可能很诱人,它是一组在调用时同步执行的顺序语句。然而,这是不正确的。
PowerShell 中的 cmdlet 是一个实现至少 3 种方法之一的对象:
- BeginProcessing() - 运行一次,当管道开始执行时
- ProcessRecord() - 运行 对于收到的每个管道项目
- EndProcessing() - 运行一次,在处理完最后一个管道项后
一旦管道开始执行,BeginProcessing()
就会在管道中的每个 cmdlet 上调用。从这个意义上说,管道中的所有 cmdlet 都是 运行ning "in parallel" - 但这种设计基本上允许我们使用单个线程执行管道 - 因此涉及多个线程的实际并行处理不是 必要 以按设计执行管道。
指出 cmdlet 在管道中并发 执行可能更准确。
我们来试试吧!
由于上面的三个方法直接映射到我们可以在高级函数中定义的begin
、process
和end
块,所以很容易看出执行的效果流.
让我们尝试将 5 个对象提供给由三个 cmdlet 组成的管道,这些 cmdlet 使用 Write-Host
报告它们的状态,看看会发生什么(见下面的代码):
PS C:\> 1..5 |first |second |third |Out-Null
请注意,PowerShell 通过 -OutBuffer
公共参数支持外部输出缓冲控制,这也会影响执行流程:
希望这是有道理的!
这是我为上面的演示编写的代码。
下面函数的 Write-Host
输出会根据我们使用的别名改变颜色,所以在 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
我在 "PowerShell Notes for professionals" 白皮书中发现了一个有趣的陈述 - "In a pipeline series each function runs parallel to the others, like parallel threads":
对吗? if "yes",是否有支持该说法的技术文档?
有点对,但完全不是真的。
这是什么意思?首先,让我们解决您的文档问题。以下内容来自 PowerShell version 3.0 Language Specification 的第 3.13 段:
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 的组成。
Cmdlet 及其构建块
将 cmdlet 视为另一个函数可能很诱人,它是一组在调用时同步执行的顺序语句。然而,这是不正确的。
PowerShell 中的 cmdlet 是一个实现至少 3 种方法之一的对象:
- BeginProcessing() - 运行一次,当管道开始执行时
- ProcessRecord() - 运行 对于收到的每个管道项目
- EndProcessing() - 运行一次,在处理完最后一个管道项后
一旦管道开始执行,BeginProcessing()
就会在管道中的每个 cmdlet 上调用。从这个意义上说,管道中的所有 cmdlet 都是 运行ning "in parallel" - 但这种设计基本上允许我们使用单个线程执行管道 - 因此涉及多个线程的实际并行处理不是 必要 以按设计执行管道。
指出 cmdlet 在管道中并发 执行可能更准确。
我们来试试吧!
由于上面的三个方法直接映射到我们可以在高级函数中定义的begin
、process
和end
块,所以很容易看出执行的效果流.
让我们尝试将 5 个对象提供给由三个 cmdlet 组成的管道,这些 cmdlet 使用 Write-Host
报告它们的状态,看看会发生什么(见下面的代码):
PS C:\> 1..5 |first |second |third |Out-Null
请注意,PowerShell 通过 -OutBuffer
公共参数支持外部输出缓冲控制,这也会影响执行流程:
希望这是有道理的!
这是我为上面的演示编写的代码。
下面函数的 Write-Host
输出会根据我们使用的别名改变颜色,所以在 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