programing

ForEach-Object - Parallel에서 사용자 지정 함수를 전달하는 방법

megabox 2023. 11. 5. 11:09
반응형

ForEach-Object - Parallel에서 사용자 지정 함수를 전달하는 방법

저는 그 기능을 전달할 방법을 찾을 수가 없습니다.변수만.

ForEach 루프 안에 기능을 넣지 않은 아이디어가 있습니까?

function CustomFunction {
    Param (
        $A
    )
    Write-Host $A
}

$List = "Apple", "Banana", "Grape" 
$List | ForEach-Object -Parallel {
    Write-Host $using:CustomFunction $_
}

enter image description here

솔루션은 원하는 만큼 간단하지 않습니다.

# Sample custom function.
function Get-Custom {
  Param ($A)
  "[$A]"
}

# Get the function's definition *as a string*
$funcDef = ${function:Get-Custom}.ToString()

"Apple", "Banana", "Grape"  | ForEach-Object -Parallel {
  # Define the function inside this thread...
  ${function:Get-Custom} = $using:funcDef
  # ... and call it.
  Get-Custom $_
}

참고: 이 답변에는 의 호출자 범위에서 스크립트 블록을 사용하는 것과 유사한 솔루션이 포함되어 있습니다.ForEach-Object -Parallel스크립트 블록입니다.

  • 참고: 기능이 모듈 자동 로딩 기능으로 알려진 위치 중 하나에 있는 모듈에 정의되어 있다면 기능 호출은 그대로 작동합니다.ForEach-Object -Parallel, 별도의 노력 없이 각 스레드에서 모듈을 가져오는 데 드는 비용이 implicit으로 발생합니다.

  • 현재 위치(작업 디렉토리)와 환경 변수(프로세스 전체에 적용되는)를 제외하고는 다음과 같은 스레드가 필요하기 때문에 위와 같은 접근 방식이 필요합니다.ForEach-Object -Parallelcreate는 호출자의 상태를 볼 수 없으며, 변수나 함수(사용자 지정 PS 드라이브 및 가져온 모듈)에 대해서도 볼 수 없습니다.

  • PowerShell 7.2.x에서는 GitHub 이슈 #12240에서 요구 시 호출자의 상태를 병렬 스레드에 복사할 수 있도록 지원하는 향상된 기능이 논의되고 있으며, 이를 통해 호출자의 기능을 자동으로 사용할 수 있습니다.

문자열을 통해 각 스레드함수를 재정의하는 것은 aux 없이 수행하기 위한 시도로서 매우 중요합니다.$funcDef변수를 사용하여 함수를 다시 정의하려고 합니다.${function:Get-Custom} = ${using:function:Get-Custom} 실패한다, 왜냐하면${function:Get-Custom}는 스크립트 블록이며 스크립트 블록을 사용합니다.$using:스코프 지정자는 교차 thread(교차 실행 공간) 문제를 방지하기 위해 명시적으로 허용되지 않습니다.

  • 하지만,${function:Get-Custom} = ${using:function:Get-Custom} 을 사용할 수 있습니다. 예를 들어 이 답변을 참조하십시오.

  • 현재 구문적으로 다음 작업을 수행할 수 있는 에서 작동하지 않습니다.& ${using:function:Get-Custom} $_,왜냐면${using:function:Get-Custom}스크립트 블록으로 보존됩니다(와 함께 unlike).Start-Job, 문자열로 역직렬화되는 경우, 그 자체로 놀라운 동작입니다 - GitHub issue #11698 참조).즉, 교차 스레드를 직접적으로 사용하는 것입니다.[scriptblock]사례들은 불분명한 실패를 야기하고, 그 이유는 이유입니다.ForEach-Object -Parallel그것을 애초에 막습니다.

  • 이와 유사한 허점으로 인해 스레드 간 문제가 발생합니다.ForEach-Object -Parallel호출자 범위에서 얻은 command-info 개체를 사용하고 있습니다.Get-Command각 나사산의 기능체로서$using:스코프: 이 또한 방지해야 하지만 PowerShell 7.2.7 이후는 아닙니다. 이 게시물GitHub 이슈 #16461을 참조하십시오.

${function:Get-Custom}namespace 변수 표기법의 한 예로, 함수를 둘 다 얻을 수 있습니다(body as a[scriptblock]instance) 및 a를 할당하여 설정(define)합니다.[scriptblock]또는 함수 본체를 포함하는 문자열.

루프 내부의 include를 사용하여 ps1 파일을 통해 병렬 프로세스에 커스텀 기능을 전부 추가하였습니다.이것은 물건들을 매우 깨끗하고 깔끔하게 유지시켜줍니다.

ForEach-Object -Parallel {
    # Include custom functions inside parallel scope
    . $using:PSScriptRoot\CustomFunctions.ps1
    # Now you can reference any function defined in the file
    My-CustomFunction
    ....

이로 인해 각 병렬 프로세스에서 기능을 로드해야 하는 오버헤드가 발생하지만, 제 경우에는 전체 처리 시간과 관련된 작은 문제였습니다.

방금 get-command를 사용하는 다른 방법을 알아냈어요 통화 교환원과 함께 작동하는 거죠$a는 결국 함수가 됩니다.정보 개체.

편집: 이것이 실 안전하지 않다고 들었는데, 왜 그런지 이해가 안 됩니다.

function hi { 'hi' }
$a = get-command hi
1..3 | foreach -parallel { & $using:a }

hi
hi
hi

그래서 저는 함수를 동적으로 추가하려는 사람들에게 유용할 수 있는 또 다른 작은 방법을 알아냈습니다. 특히 함수가 배열되어 있을 때와 같이 함수의 이름을 미리 알지 못할 수도 있습니다.

# Store the current function list in a variable
$initialFunctions=Get-ChildItem Function:

# Source all .ps1 files in the current folder and all subfolders
Get-ChildItem . -Recurse | Where-Object { $_.Name -like '*.ps1' } |
     ForEach-Object { . "$($_.FullName)" }

# Get only the functions that were added above, and store them in an array
$functions = @()
Compare-Object $initialFunctions (Get-ChildItem Function:) -PassThru |
    ForEach-Object { $functions = @($functions) + @($_) }

1..3 | ForEach-Object -Parallel {
    # Pull the $functions array from the outer scope and set each function
    # to its definition
    $using:functions | ForEach-Object {
        Set-Content "Function:$($_.Name)" -Value $_.Definition
    }
    # Call one of the functions in the sourced .ps1 files by name
    SourcedFunction $_
}

이것의 주된 "꼼수"는 다음을 사용하는 것입니다.Set-Content와 함께Function:기능 이름과 더불어 PowerShell은 기본적으로 각 항목을 처리합니다.Function:오솔길로서

이것은 당신이 다음의 출력을 고려할 때 타당합니다.Get-PSDrive. 각 항목은 동일한 방식(즉, 콜론과 함께)으로 "드라이브"로 사용될 수 있기 때문입니다.

언급URL : https://stackoverflow.com/questions/61273189/how-to-pass-a-custom-function-inside-a-foreach-object-parallel

반응형