2

我想对我的一个脚本实施-parallel Switch

非并行版本:

  $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#>)。

这可能吗?

4

2 回答 2

1
$arguments = @{ }
if ($myParallel) {
    $arguments = @{ parallel = $true; $throttlelimit = 10 }
}
$tmpArray | ForEach-Object @arguments {
...
}
于 2021-08-30T13:48:52.907 回答
1

您可以将可重用代码定义为脚本块,但请注意,您将无法直接在脚本块中使用它,而是必须通过将其字符串表示传递给静态方法来重新创建它;使用一个简化的例子:ForEach-Object -Parallel[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 问题 #12378讨论了这种行为,包括一种可能的增强功能,可以让ForEach-Object自己以线程安全的方式自动重新创建脚本块。

    • 更一般地说,GitHub 问题 #12240提出了一种选择加入机制,允许将调用者的定义复制到每个线程,从而$using:无需引用。
于 2021-08-30T13:49:11.753 回答