2016-08-27 5 views
0

scarpt가 있는데, 잘 작동하지만 멀티 스레딩을 사용하여 약간 속도를 높이고 싶습니다. 문제는 많은 코드를 변경하지 않고서는 어렵다는 것입니다. 나는 새로운 분리 된 범위로 일자리를 피하고 싶지만 불가능한 것처럼 보입니다. 또한 시작 작업은 정말 느리고 실행을 시작하려면 ~ 150 밀리 초가 필요합니다. 작업을 피할 수있는 방법이 없습니까? 아니면 최소한이 스크립트가 예상대로 작동하지 않을까요?Powershell이 ​​완성 된 스크립트에 멀티 스레딩을 추가했습니다.

Param(
    [int]$arg1 = 2, [int]$arg2 = 3 
) 
$functionDoSomething = { 
    function doSomething($inp) { 
     return $inp + 10 
    } 
} 

function doSomething($inp) { 
    return $inp + 10 
} 

# time: 1523337 ticks 
Measure-Command { 
    Start-Job -Name Job1 -InitializationScript $functionDoSomething -ScriptBlock { 
     return doSomething ($arg1 + $arg2) 
    } -ArgumentList $arg1, $arg2 
    Wait-Job Job1 
    $var2 = Receive-Job Job1 # result is 10, so arguements aren't passed correctly, trick with @($arg1, arg2) = the same result 
} 

# time: 6867 ticks 
Measure-Command { 
    $var3 = doSomething ($arg1 + $arg2) # result is 15 
} 

답변

0
# Have no fear - Invoke-Parallel is here. Hoping that I can help steer you in the right direction. Let me show you some pseudo code that can point you in the right direction. 

# You need a list of objects in which you want to perform an operation for 
$listOfComputers = @(
'1' 
'2' 
'3' 
) 

# Pipe your array to Invoke-Parallel which takes care of opening threads depending on the amount of objects piped in. 
# If you want to control the amount of simultaneous threads simply help Invoke-Parallel -ShowWindow to see how 
$results = $listOfComputers | Invoke-Parallel -ScriptBlock { 
function doSomething($inp) 
{ 
    return [int]$inp + 10 
} 
if ($_ -eq '1') { Start-Sleep -Seconds 15; Write-Verbose 'Waited 15s' } # Adding this so you can see that this script block is running in a multi-threaded fashion 
# $_ refers to the values inside of $listOfComputers 
return doSomething ($_) 
} -Verbose 

$results 

<# Notice how 11 comes up last 
12 
13 
11 
#> 
+0

답변 해 주셔서 감사합니다. 하지만이 솔루션에는 한 가지 문제가 있습니다. 스크립트는 엔터프라이즈 환경에서 작동하며, PS가 아닌 외부 모듈을 추가하는 것이 다소 문제가됩니다. 또한 스크립트는 하나의 시스템에서 작동하기 때문에 새로운 스레드에서 스크립트의 일부를 호출하여 처리 속도를 높일 수 있습니다. 이 솔루션이 그렇게 작동한다면 확실하지 않습니다. – PatrykMilewski

+0

이것은 외부 모듈이 아닙니다. 그것은 단순히 당신을 위해 일을 돕는 기능입니다. 왜 바퀴를 다시 발명해야합니까? Invoke-Parallel.ps1 파일을 다운로드하기 만하면됩니다. 자체 스크립트의 시작 부분에이 함수를로드하면 Import-Module 'Invoke-Parallel.ps1'을 사용하여 소비 할 수 있습니다. 이 함수는 Start-Job과 그 오버 헤드를 우회하는 .NET System.Management.Automation.Runspaces를 사용합니다. –

+0

다음 시도해 보겠습니다. – PatrykMilewski

0

먼저 (제대로 인수를 전달에는 두 배 기능), 실행 영역과 RunSpacePool 들여다 보지. runspace를 만들 때 기본값 이외의 모듈이로드되도록 지정할 수 있습니다. 자세한 내용은 http://www.get-blog.com/?p=189을 참조하십시오.

$ScriptBlock = { 
param([string]$forinput) 
    "Do something with $forinput" 

    [PSCusomObject]@{ 
    Line1="Something" 
    Line2="Something done to $forinput" 
    }#end of custom object output 

}#end script block 

#Create Runspace pool, 100 min and max. 
#Example data contained within $item.property 
$RunspacePool = [RunspaceFactory]::CreateRunspacePool(100,100) 
$RunspacePool.Open() 
$Jobs = 
foreach ($item in $VariableContainsListOfInput) 
{ 
    $Job = [powershell]::Create(). 
    AddScript($ScriptBlock). 
    AddArgument($item.property) 
    $Job.RunspacePool = $RunspacePool 

[PSCustomObject]@{ 
    Pipe = $Job 
    Result = $Job.BeginInvoke() 
} 
} 

DO{Start-sleep -seconds 1 
}While($Jobs.Result.IsCompleted -contains $false) 

#Loop through jobs, pipe EndInvoke data from runspace into Export-CSV 
$(ForEach ($Job in $Jobs) 
{ $Job.Pipe.EndInvoke($Job.Result) }) | 
Export-Csv -Path "$FullPath\$file" -NoTypeInformation 
#clean up runspace 
$RunspacePool.Close() 
$RunspacePool.Dispose() 
+0

정말 멋진 솔루션입니다. 감사합니다. 그러나 Alberto의 대답에서 Invoke-Parallel을 사용하는 것이 훨씬 간단하고 비슷한 결과를 얻는다고 생각합니다 (당연히 속도가 느립니다). 나는 그것을 시도해 볼 것인데, 단지 복잡하게 보일 수도 있습니다 : p – PatrykMilewski

+0

당신은 환영합니다! 그것은 나에게도 복잡해 보였습니다. 중요한 부분은 스크립트 블록과'Export-CSV'로 보내지는 출력물 인'PSCustomObject'입니다. 여기서 보너스는 다른 함수/스크립트로 파이프 될 수있는 객체를 생성 할 수 있다는 것입니다 . PowerShell의 기능은 Objects입니다. – user4317867