Powershell peut-il exécuter des commandes en parallèle?

J'ai un script powershell pour faire quelques traitement par lots sur un tas d'images et j'aimerais faire quelques traitement en parallèle. Powershell semble avoir des options de traitement en arrière-plan telles que start-job, wait-job, etc, mais la seule bonne ressource que j'ai trouvée pour faire du travail parallèle était d'écrire le texte d'un script et d'exécuter ceux-ci (PowerShell Multithreading )

Idéalement, je voudrais quelque chose qui s'apparente à parallel foreach dans.net 4.

Quelque chose d'assez sans apparence comme:

foreach-parallel -threads 4 ($file in (Get-ChildItem $dir))
{
   .. Do Work
}

Peut-être que je ferais mieux de tomber en c#...

99
demandé sur Alan Jackson 2010-10-25 20:00:38

5 réponses

Vous pouvez exécuter des travaux parallèles dans Powershell 2 en utilisant Travaux D'arrière-plan. Consultez Start-Job et les autres applets de commande job.

# Loop through the server list
Get-Content "ServerList.txt" | %{

  # Define what each job does
  $ScriptBlock = {
    param($pipelinePassIn) 
    Test-Path "\\$pipelinePassIn\c`$\Something"
    Start-Sleep 60
  }

  # Execute the jobs in parallel
  Start-Job $ScriptBlock -ArgumentList $_
}

Get-Job

# Wait for it all to complete
While (Get-Job -State "Running")
{
  Start-Sleep 10
}

# Getting the information back from the jobs
Get-Job | Receive-Job
75
répondu Steve Townsend 2015-06-16 19:15:27

La réponse de Steve Townsend est correcte en théorie mais pas en pratique comme l'a souligné @likwid. Mon code révisé prend en compte le barrière du contexte d'emploi--rien ne franchit cette barrière par défaut! La variable automatique $_ peut donc être utilisée dans la boucle mais ne peut pas être utilisée directement dans le bloc de script car elle se trouve dans un contexte distinct créé par le travail.

Pour passer des variables du contexte parent au contexte enfant, utilisez le paramètre -ArgumentList sur Start-Job envoyer et à utiliser param à l'intérieur du bloc de script pour le recevoir.

cls
# Send in two root directory names, one that exists and one that does not.
# Should then get a "True" and a "False" result out the end.
"temp", "foo" | %{

  $ScriptBlock = {
    # accept the loop variable across the job-context barrier
    param($name) 
    # Show the loop variable has made it through!
    Write-Host "[processing '$name' inside the job]"
    # Execute a command
    Test-Path "\$name"
    # Just wait for a bit...
    Start-Sleep 5
  }

  # Show the loop variable here is correct
  Write-Host "processing $_..."

  # pass the loop variable across the job-context barrier
  Start-Job $ScriptBlock -ArgumentList $_
}

# Wait for all to complete
While (Get-Job -State "Running") { Start-Sleep 2 }

# Display output from all jobs
Get-Job | Receive-Job

# Cleanup
Remove-Job *

(j'aime généralement fournir une référence à la documentation PowerShell comme preuve à l'appui mais, hélas, ma recherche a été infructueuse. Si vous savez où la séparation du contexte est documentée, postez un commentaire ici pour me le faire savoir!)

82
répondu Michael Sorens 2011-07-21 17:35:36

Http://gallery.technet.microsoft.com/scriptcenter/Invoke-Async-Allows-you-to-83b0c9f0

J'ai créé un invoke-async qui vous permet d'exécuter plusieurs blocs de script / cmdlets/fonctions en même temps. ceci est idéal pour les petits travaux (analyse de sous-réseau ou requête wmi contre 100 de machines) car la surcharge pour créer un espace d'exécution par rapport à l'Heure de démarrage du travail de démarrage est assez drastique. Il peut être utilisé comme.

Avec scriptblock,

$sb = [scriptblock] {param($system) gwmi win32_operatingsystem -ComputerName $system | select csname,caption} 

$servers = Get-Content servers.txt 

$rtn = Invoke-Async -Set $server -SetParam system  -ScriptBlock $sb

Juste applet de commande/fonction

$servers = Get-Content servers.txt 

$rtn = Invoke-Async -Set $servers -SetParam computername -Params @{count=1} -Cmdlet Test-Connection -ThreadCount 50
8
répondu jrich523 2013-03-01 16:43:00

Les travaux D'arrière-plans sont coûteux à configurer et ne sont pas réutilisables. PowerShell MVP Oisin Grehan a un bon exemple de PowerShell multi-threading http://www.nivot.org/2009/01/22/CTP3TheRunspaceFactoryAndPowerShellAccelerators.aspx

(25/10/2010 le site est en panne):

J'ai utilisé un script Oisin adapté pour une utilisation dans une routine de chargement de données ici:

Http://rsdd.codeplex.com/SourceControl/changeset/view/a6cd657ea2be#Invoke-RSDDThreaded.ps1

6
répondu Chad Miller 2010-10-25 19:59:06

Pour compléter les réponses précédentes, vous pouvez également utiliser Wait-Job attendre pour tous les travaux à effectuer:

For ($i=1; $i -le 3; $i++) {
    $ScriptBlock = {
        Param (
            [string] [Parameter(Mandatory=$true)] $increment
        )

        Write-Host $increment
    }

    Start-Job $ScriptBlock -ArgumentList $i
}

Get-Job | Wait-Job | Receive-Job
0
répondu Thomas 2018-10-02 04:50:04