Powershell 实现 Switch 语句

Powershell implement Switch Statement

我想实施一个 -平行线 切换到我的一个脚本

非并行版本:

  $tmpArray | ForEach-Object {
          #region ... local Variables
          $stepWidthLocal = $stepWidth
<#
my code
#>

并行功能:

  $tmpArray | ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel {
          #region ... local Variables
          $stepWidthLocal = $using:stepWidth
<#
my code
#>

我不想要的是:

$myParallel = $true
if ($myParallel) {
  $tmpArray | ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel {
    #region ... local Variables
    $stepWidthLocal = $using:stepWidth
    <#
    my code
    #>
  } #end $tmpArray | ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel
} #end if($myParallel) 
else {
  $tmpArray | ForEach-Object {
    #region ... local Variables
    $stepWidthLocal = $stepWidth
    <#
my code
#>
  } #end $tmpArray | ForEach-Object {
} #end else {

我想要这样的东西:


$myCode = <#
define my Codeblock
#>
$myParallel = $true
if ($myParallel) {
  $tmpArray | ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel {
    #region ... local Variables
    $stepWidthLocal = $using:stepWidth
    $myCode
  } #end $tmpArray | ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel
} #end if($myParallel) 
else {
  $tmpArray | ForEach-Object {
    #region ... local Variables
    $stepWidthLocal = $stepWidth
    $myCode
  } #end $tmpArray | ForEach-Object {
} #end else {

现在我想创建某种 switch 语句而不复制整个代码(块 <# my code#>)。

这可能吗?

$arguments = @{ }
if ($myParallel) {
    $arguments = @{ parallel = $true; $throttlelimit = 10 }
}
$tmpArray | ForEach-Object @arguments {
...
}

您可以将可重用代码定义为script block, but note that you won't be able to use it directly in your ForEach-Object -Parallel script block and instead have to recreate it there, via its string representation passed to the static [scriptblock]::Create()方法;使用一个简化的例子:

# Your reusable code block.
# Note the .ToString() call to obtain its string representation.
$myCodeSource = {
  "hi from thread $([System.Threading.Thread]::CurrentThread.ManagedThreadId)"
}.ToString()


1, 2 | ForEach-Object -Parallel { 
  # ...
  # Note: You can pass arguments, if the script block is prepared to handle them.
  & ([scriptblock]::Create($using:myCodeSource)) 
}

注意: 包含一个类似的解决方案,用于在 ForEach-Object -Parallel 脚本块中使用来自调用方范围的 函数

以上输出如下:

hi from thread 35
hi from thread 36

注意(从 PowerShell 7.2 开始):

  • ForEach-Object -Parallel 主动 防止 直接使用来自调用者范围(通过 $using: 访问)范围的脚本块,因为使用跨线程的脚本块会导致线程安全问题;然而,奇怪的是,相关的 Start-ThreadJob 确实 通过 $using: 接受脚本块——尽管这可能是一个疏忽。

    • 通过字符串 表示重新创建 脚本块,如上所示,可以解决此限制。
  • GitHub issue #12378 讨论了这种行为,包括让 ForEach-Object 本身以线程安全的方式自动重新创建脚本块的可能增强。

    • 更一般地说,GitHub issue #12240 提出了一种选择加入机制,允许将调用者的定义复制到每个线程,从而无需 $using: 引用。