Почему функция не вызывается 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
}

Что не так со сценарием?

Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
4
0
33
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Поскольку testFct не существует в области вашего ThreadJob, вам нужно сначала сохранить определение функции, а затем передать его в область выполнения и определить там функцию, как показано в этот ответ.

Другая проблема заключается в попытке ссылаться на один и тот же $input более одного раза. Из-за характера автоматическая переменная $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.

В качестве обходного пути вы можете обернуть переменную в Оператор подвыражения массива @( ) или Оператор подвыражения $( ), чтобы сохранить перечисленный вывод в новой переменной.

Вот простой пример того, что объяснено выше:

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

Наконец, ваш сценарий на самом деле не многопоточность, это потому, что вы сохраняете задание внутри своего цикла, а затем ожидаете его последовательно вместо того, чтобы запускать все задания сразу, а затем ждать их всех.

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

Другие вопросы по теме