2012-10-07 11 views
15

Non sono sicuro se chiamarlo necessario per multi-threading, basato sul lavoro o asincrono, ma fondamentalmente ho una funzione di script di PowerShell che richiede diversi parametri e io è necessario chiamarlo più volte con parametri diversi e farlo funzionare in parallelo.Come eseguire una funzione di Powershell più volte in parallelo

Attualmente, io chiamo la funzione come questa:

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

Come posso chiamare questo più volte senza attendere per ogni chiamata a Execute ritorno al chiamante?

Attualmente sto correndo v2.0 ma posso aggiornare, se necessario,

EDIT: ecco quello che ho finora, che non funziona:

$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 

ottengo un errore:

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

EDIT2: ho modificato il mio script ma ottengo ancora l'errore menzionato sopra. Ecco il mio 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 

risposta

29

Nessun aggiornamento necessario. Definire un blocco di script e utilizzare Start-Job per eseguire il blocco di script tutte le volte necessarie. Esempio:

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

$foo = "foo" 

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

Il blocco di script accetta 2 parametri $a e $b che sono passati dall'opzione -ArgumentList. Nell'esempio sopra, i compiti sono $_$a e $foo$b. $foo è solo un esempio per un parametro configurabile, ma statico.

Esegui Get-Job | Remove-Job a un certo punto per rimuovere i lavori completati dalla coda (o Get-Job | % { Receive-Job $_.Id; Remove-Job $_.Id } se si desidera recuperare l'output).

+0

sto ancora attraversando un periodo difficile mappatura la soluzione per ottenere il mio script per funzionare. Sto per iniziare in modo semplice, e cerco di avviare Start-Job per eseguire il mio scriptblock con gli argomenti richiesti dalla mia funzione personalizzata Execute. Forse puoi espandere? $ Foo è un parametro in aggiunta a quelli specificati da param ($ a, $ b)? – JohnZaj

+0

Vedo ora, grazie. Ho comunque ricevuto l'errore. Se non sei sicuro di cosa potrebbe essere, creerò solo post/domanda separati. – JohnZaj

+0

Per scopi di test sostituire la chiamata della funzione 'Execute()' con codice che fa semplicemente eco ai parametri. Funziona? Se lo fa, il problema si trova nella funzione che vuoi chiamare. –

16

Ecco uno scriptblock falso rapido per le esigenze di prova:

$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)." 
} 

Questo scriptblock può quindi essere trasmesso a Start-Job, con per esempio 3 parametri (10, 15, 35)

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

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

Questo crea 3 lavori, li assegna alla variabile $jobs, li esegue in parallelo e quindi attende che questi 3 lavori finiscano e recupera i risultati:

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. 

Questo non ha preso 90 secondi per eseguire, solo 30.

Una delle parti difficili è fornire -Argumentlist a Start-Job, e comprendono un blocco param() all'interno ScriptBlock. Altrimenti, i tuoi valori non saranno mai visti dal blocco di script.

3

Mi dispiace che tutti abbiano perso il tuo problema: so che è troppo tardi ora, ma ...

Questo errore è causato dal fatto che manca una virgola tra $ username e $ password nell'elenco.

È possibile verificare fuori con questo frammento, che ho modellato fuori delle risposte precedenti:

$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

È possibile utilizzare un'alternativa che può essere più veloce di posti di lavoro che invocano se la funzione non è un lungo in esecuzione uno . Il thread massimo è 25 e sto solo richiamando questa funzione 10 volte, quindi mi aspetto che il mio tempo di esecuzione totale sia di 5 secondi. Puoi inserire Measure-Command attorno all'istruzione 'results =' per visualizzare le statistiche.

Esempio:

$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 
Problemi correlati