为什么 Start-ThreadJob 没有调用该函数?

Why is the function not called by Start-ThreadJob?

我想通过我的脚本备份一些数据。所有数据都应压缩在一个单独的线程中。但是有两件事出了问题:

  1. 从未调用函数 testFct - 指示:没有“内部:...”。
  2. 缺少 ZipSource 参数 - 查看输出。

调用脚本结果:

> .\Backup.ps1
outside: -What:  Data A   -ZipSource     -ZipDest  C:\Users\xyz\AppData\Local\Temp  -Timestamp "20220517-002854
outside: -What:  Data B   -ZipSource     -ZipDest  C:\Users\xyz\AppData\Local\Temp  -Timestamp "20220517-002854
>

这是我的脚本:

class BackupContentData
{
    [ValidateNotNullOrEmpty()][string]$What
    [ValidateNotNullOrEmpty()][string]$ZipSource
}
$bcd = @(
    [BackupContentData]@{ What="Data A";   ZipSource="$env:USERPROFILE\Documents\a_file.txt";}
    [BackupContentData]@{ What="Data B";   ZipSource="$env:USERPROFILE\Documents\b_file.txt";}
)

function testFct {
    param([string]$What, [string]$ZipSource, [string]$ZipDest, [string]$Timestamp)
    
    Write-Host "inside: -What: "$What"  -ZipSource "$ZipSource"  -ZipDest "$ZipDest"  -Timestamp "$Timestamp
}


$timestamp="$(get-date -f yyyyMMdd-HHmmss)"

foreach ($e in $bcd) {
    $job = Start-ThreadJob  -Name $e.What  -InputObject $e  -ScriptBlock {
        Invoke-Expression "function getTest {$using:testFct}"
    
        Write-Host "outside: -What: "$input.What"  -ZipSource "$input.ZipSource"  -ZipDest "$env:Temp"  -Timestamp ""$(get-date -f yyyyMMdd-HHmmss)"
    
        getTest -What "$input.What"  -ZipSource "$input.ZipSource"  -ZipDest "$env:Temp"  -Timestamp "$(get-date -f yyyyMMdd-HHmmss)"
    }

    Receive-Job $job -AutoRemoveJob -Wait
}

脚本有什么问题?

由于 testFct 不存在于您的 ThreadJob 范围内,您需要首先存储函数的定义,然后将其传递到运行空间范围并在那里定义函数,如 [=23= 中所示].

另一个问题是试图多次引用同一个 $input。由于 automatic variable $input 的性质,您只能在 脚本块中引用此变量一次 :

Since $input is an enumerator, accessing any of its properties causes $input to no longer be available. You can store $input in another variable to reuse the $input properties.

作为解决方法,您可以将变量包装在 Array subexpression operator @( ) or the Subexpression operator $( ) 中以将枚举输出存储在新变量中。

这是上面解释的一个简单示例:

Start-ThreadJob -InputObject 'Hello World' -ScriptBlock {
    "1. $input"
    "2. $input"
} | Receive-Job -AutoRemoveJob -Wait

# This outputs:
# 1. Hello World
# 2.

# And the workaround
Start-ThreadJob -InputObject 'Hello World' -ScriptBlock {
    # This would also work:
    # $thisInput = foreach($i in $input) { $i }

    $thisInput = $($input)
    "1. $thisInput"
    "2. $thisInput"
} | Receive-Job -AutoRemoveJob -Wait

# Outputs:
# 1. Hello World
# 2. Hello World

最后,您的脚本实际上并不是 multi-threading,这是因为您将作业存储在循环中,然后依次等待它 而不是一次启动所有作业然后等待所有作业

class BackupContentData {
    [ValidateNotNullOrEmpty()] [string] $What
    [ValidateNotNullOrEmpty()] [string] $ZipSource
}
function testFct {
    param([string]$What, [string]$ZipSource, [string]$ZipDest, [string]$Timestamp)
    Write-Host "inside: -What: $What -ZipSource $ZipSource -ZipDest $ZipDest -Timestamp $Timestamp"
}

# definition of the function is stored here
$def = ${function:testFct}.ToString()

$bcd = @(
    [BackupContentData]@{ What="Data A"; ZipSource="$env:USERPROFILE\Documents\a_file.txt" }
    [BackupContentData]@{ What="Data B"; ZipSource="$env:USERPROFILE\Documents\b_file.txt" }
)

$job = foreach ($e in $bcd) {
    Start-ThreadJob -Name $e.What -InputObject $e -ScriptBlock {
        $thisObject = $($input)
        # Define a new function with name `getTest` in this scope using `testFct` definition
        ${function:getTest} = $using:def
        Write-Host "outside: -What: $($thisObject.What) -ZipSource $($thisObject.ZipSource) -ZipDest $env:Temp -Timestamp $(get-date -f yyyyMMdd-HHmmss)"
        getTest -What $thisObject.What -ZipSource $thisObject.ZipSource -ZipDest $env:Temp -Timestamp (Get-Date -f yyyyMMdd-HHmmss)
    }
}
$job | Receive-Job -AutoRemoveJob -Wait

您可以从中得到的输出:

outside: -What: Data A -ZipSource C:\Users\user\Documents\a_file.txt -ZipDest C:\Users\user\AppData\Local\Temp -Timestamp 20220516-202251
inside: -What: Data A -ZipSource C:\Users\user\Documents\a_file.txt -ZipDest C:\Users\user\AppData\Local\Temp -Timestamp 20220516-202251
outside: -What: Data B -ZipSource C:\Users\user\Documents\b_file.txt -ZipDest C:\Users\user\AppData\Local\Temp -Timestamp 20220516-202251
inside: -What: Data B -ZipSource C:\Users\user\Documents\b_file.txt -ZipDest C:\Users\user\AppData\Local\Temp -Timestamp 20220516-202251