Powershell 实现 Switch 语句 [英] Powershell implement Switch Statement

查看:69
本文介绍了Powershell 实现 Switch 语句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

非并行版本:

 $tmpArray |ForEach-Object {#region ... 局部变量$stepWidthLocal = $stepWidth<#我的代码#>

并行功能:

 $tmpArray |ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel {#region ... 局部变量$stepWidthLocal = $using:stepWidth<#我的代码#>

我不想要的是:

$myParallel = $true如果($myParallel){$tmpArray |ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel {#region ... 局部变量$stepWidthLocal = $using:stepWidth<#我的代码#>} #end $tmpArray |ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel} #end if($myParallel)别的 {$tmpArray |ForEach-Object {#region ... 局部变量$stepWidthLocal = $stepWidth<#我的代码#>} #end $tmpArray |ForEach-Object {} #结束其他{

我想要这样的东西:

<预><代码>$myCode = <#定义我的代码块#>$myParallel = $true如果($myParallel){$tmpArray |ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel {#region ... 局部变量$stepWidthLocal = $using:stepWidth$myCode} #end $tmpArray |ForEach-Object -ThrottleLimit ($parallelBlocks * 10) -Parallel} #end if($myParallel)别的 {$tmpArray |ForEach-Object {#region ... 局部变量$stepWidthLocal = $stepWidth$myCode} #end $tmpArray |ForEach-Object {} #结束其他{

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

这可能吗?

解决方案

您可以将可重用代码定义为 脚本块,但请注意,您将无法直接在您的ForEach-Object -Parallel 脚本块,而必须重新创建它 在那里,通过它的 string 表示传递给静态 [scriptblock]::Create() 方法;使用一个简化的例子:

# 你的可重用代码块.# 注意 .ToString() 调用以获取其字符串表示.$myCodeSource = {您好,来自线程 $([System.Threading.Thread]::CurrentThread.ManagedThreadId)"}.ToString()1, 2 |ForEach-Object -Parallel {# ...# 注意:如果脚本块准备好处理它们,您可以传递参数.&([脚本块]::创建($using:myCodeSource))}

注意:此答案包含使用来自函数的类似解决方案ForEach-Object -Parallel 脚本块中调用者的范围.

上面的输出类似于以下内容:

hi from thread 35来自线程 36 的你好

注意(从 PowerShell 7.2 开始):

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

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

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

I would like to implement a -parallel Switch to one of my skripts

Non Parallel Version:

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

Parallel Funktion:

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

What I dont want is:

$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 {

I want something like this:


$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 {

Now I want to create some kind of switch statement without duplicating the entire code (block <# my code#>).

is this possible?

解决方案

You can define the reusable code as a 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() method; using a simplified example:

# 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)) 
}

Note: This answer contains an analogous solution for using a function from the caller's scope in a ForEach-Object -Parallel script block.

The above output something like the following:

hi from thread 35
hi from thread 36

Note (as of PowerShell 7.2):

  • ForEach-Object -Parallel actively prevents direct use of script blocks from the caller's scope (accessed via the $using:) scope, because using script blocks across threads can lead to thread-safety issues; curiously, however, the related Start-ThreadJob does accept script blocks via $using: - though that may have been an oversight.

    • Recreating a script block via its string representation, as shown above, works around this limitation.
  • GitHub issue #12378 discusses this behavior, including a possible enhancement to let ForEach-Object itself automatically recreate the script block in a thread-safe manner.

    • More generally, GitHub issue #12240 proposes an opt-in mechanism that would allow copying the caller's definitions to each thread, making $using: references unnecessary.

这篇关于Powershell 实现 Switch 语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆