2012-10-07 10 views
15

Nie jestem pewien, czy należy to nazwać potrzebą wielowątkowości, zadania opartego na zadaniu, czy asynchronicznej, ale zasadniczo mam funkcję skryptu Powershell, która ma kilka parametrów i trzeba wywoływać go kilka razy z różnymi parametrami i uruchamiać równolegle.Sposób wykonywania funkcji Powershell kilka razy równolegle

Obecnie mogę wywołać funkcję tak:

Execute "param1" "param2" "param3" "param4" 

Jak mogę nazwać to wiele razy, nie czekając na wezwanie do wykonania każdego powrót do rozmówcy?

Obecnie używam v2.0 ale mogę aktualizować w razie potrzeby

EDIT: oto co mam do tej pory, co nie działa:

$cmd = { 
    param($vmxFilePath,$machineName,$username,$password,$scriptTpath,$scriptFile,$uacDismissScript,$snapshotName) 
    Execute $vmxFilePath $machineName $username $password $scriptTpath $scriptFile $uacDismissScript $snapshotName 
} 

Start-Job -ScriptBlock $cmd -ArgumentList $vmxFilePath, $machineName, $username $password, $scriptTpath, $scriptFile, $uacDismissScript, $snapshotName 

pojawia się błąd:

cannot convert 'system.object[]' to the type 'system.management.automation.scriptblock' required by parameter 'initializationscript'. specified method is not supported 

EDIT2: Zmodyfikowałem skrypt, ale nadal dostaję powyższy błąd. Oto mój mod:

$cmd = { 
    param($vmxFilePath,$machineName,$username,$password,$scriptTpath,$scriptFile,$uacDismissScript,$snapshotName) 
    Execute $vmxFilePath $machineName $username $password $scriptTpath $scriptFile $uacDismissScript $snapshotName 
} 

Start-Job -ScriptBlock $cmd -ArgumentList $vmxFilePath, $machineName, $username $password, $scriptTpath, $scriptFile, $uacDismissScript, $snapshotName 

Odpowiedz

29

Nie jest wymagana żadna aktualizacja. Zdefiniuj blok skryptu i użyj Start-Job, aby uruchomić blok skryptu tyle razy, ile potrzeba. Przykład:

$cmd = { 
    param($a, $b) 
    Write-Host $a $b 
} 

$foo = "foo" 

1..5 | ForEach-Object { 
    Start-Job -ScriptBlock $cmd -ArgumentList $_, $foo 
} 

Blok scenariusz trwa 2 parametry $a i $b, które są przekazywane przez opcję -ArgumentList. W powyższym przykładzie przypisania są następujące: $_$foo to tylko przykład konfigurowalnego, ale statycznego parametru.

Uruchom w pewnym momencie Get-Job | Remove-Job, aby usunąć zakończone zadania z kolejki (lub Get-Job | % { Receive-Job $_.Id; Remove-Job $_.Id }, jeśli chcesz odzyskać dane wyjściowe).

+0

ciągle mam twardy czas mapowanie swoje rozwiązanie, aby mój własny skrypt do pracy. Zacznę od prostoty i po prostu staram się uruchomić Start-Job, aby uruchomić mój blok skryptów z argumentami wymaganymi przez moją niestandardową funkcję Execute. Może możesz rozwinąć? Czy $ foo jest parametrem oprócz parametrów określonych przez parametr ($ a, $ b)? – JohnZaj

+0

Widzę teraz, dzięki. Nadal dostaję błąd. Jeśli nie masz pewności, co to może być, po prostu utworzę osobny wpis/pytanie. – JohnZaj

+0

Do celów testowych zamień wywołanie funkcji 'Execute()' na kod, który po prostu odtwarza parametry. Czy to działa? Jeśli tak, problem leży w funkcji, którą chcesz wywołać. –

16

Oto szybkie fałszywe scriptblock w celu testowania:

$Code = { 
    param ($init) 
    $start = Get-Date 
    (1..30) | % { Start-Sleep -Seconds 1; $init +=1 } 
    $stop = Get-Date 
    Write-Output "Counted from $($init - 30) until $init in $($stop - $start)." 
} 

to scriptblock może następnie być przekazywany do Start-Job, na przykład z 3 parametrów (10, 15, 35)

$jobs = @() 
(10,15,35) | % { $jobs += Start-Job -ArgumentList $_ -ScriptBlock $Code } 

Wait-Job -Job $jobs | Out-Null 
Receive-Job -Job $jobs 

Powoduje utworzenie 3 zadań, przypisanie ich do zmiennej $jobs, uruchomienie ich równolegle, a następnie oczekiwanie na wykonanie tych 3 zadań i pobranie wyników:

Counted from 10 until 40 in 00:00:30.0147167. 
Counted from 15 until 45 in 00:00:30.0057163. 
Counted from 35 until 65 in 00:00:30.0067163. 

nie trzeba było 90 sekund do wykonania tylko 30

jedną z trudności jest zapewnienie części -Argumentlist do Start-Job i obejmują param() bloku wewnątrz ScriptBlock. W przeciwnym razie twoje wartości nigdy nie zostaną zauważone przez skryptblok.

3

Przykro mi, że wszyscy przegapili twój problem - wiem, że teraz jest już za późno, ale ...

Ten błąd jest spowodowany brakiem przecinka między $ nazwa użytkownika i $ hasło na liście.

Można przetestować go z tego fragmentu, który ja modelowanego off z poprzednich odpowiedzi:

$cmd = { 
    param($a, $b, $c, $d) 
} 
$foo = "foo" 
$bar = "bar" 
start-job -scriptblock $cmd -ArgumentList "a", $foo, $bar, "gold" #added missing comma for this to work 
2

Można wykorzystać alternatywne, które mogą być szybciej niż zatrudnienie powołując jeśli funkcja nie jest długi uruchomiony jeden . Maksymalna liczba wątków wynosi 25, a ja tylko wywołuję tę funkcję 10 razy, więc spodziewam się, że mój całkowity czas działania wyniesie 5 sekund. Możesz owinąć Measure-Command wokół instrukcji 'results =', aby zobaczyć statystyki.

Przykład:

$ScriptBlock = { 
     Param ([int]$RunNumber) 

     Start-Sleep -Seconds 5 
     Return $RunNumber 

    } 



    $runNumbers = @(1..10) 


    $MaxThreads = 25 
    $runspacePool = [RunspaceFactory ]::CreateRunspacePool(1, $MaxThreads) 
    $runspacePool.Open() 


    $pipeLines = foreach($num in $runNumbers){ 

           $pipeline = [powershell]::Create() 
           $pipeline.RunspacePool = $runspacePool 
           $pipeline.AddScript($ScriptBlock) | Out-Null 
           $pipeline.AddArgument($num) | Out-Null 

           $pipeline | Add-Member -MemberType NoteProperty -Name 'AsyncResult' -Value $pipeline.BeginInvoke() -PassThru 
        } 



    #obtain results as they come. 
    $results = foreach($pipeline in $pipeLines){ 
         $pipeline.EndInvoke($pipeline.AsyncResult) 
       } 


    #cleanup code. 
    $pipeLines | % { $_.Dispose()} 
    $pipeLines = $null 
    if ($runspacePool) { $runspacePool.Close()} 

    #your results 
    $results 
Powiązane problemy