Может ли Powershell выполнять команды параллельно?


У меня есть сценарий powershell для выполнения пакетной обработки на куче изображений, и я хотел бы сделать некоторую параллельную обработку. Powershell, похоже, имеет некоторые параметры фоновой обработки, такие как start-job, wait-job и т. д., Но единственным хорошим ресурсом, который я нашел для параллельной работы, было написание текста сценария и запуск этих ( Многопоточность PowerShell)

В идеале, я хотел бы что-то похожее на параллельный foreach в .net 4.

что-то довольно кажущийся, как:

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

может быть, мне лучше просто опуститься до c#...

5 99

5 ответов:

вы можете выполнять параллельные задания в Powershell 2 с помощью Фоновые Задания. Проверьте Start-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

ответ Стива Таунсенда верен в теории, но не на практике, как указал @likwid. Мой пересмотренный код учитывает работа-контексте барьер--ничего не пересекает этот барьер по умолчанию! Автоматический

чтобы передать переменные из родительского контекста в дочерний контекст, используйте элемент -ArgumentList параметр on Start-Job чтобы отправить его и использовать param внутри блока скрипта, чтобы получить его.

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 *

(Я обычно хотел бы предоставить ссылку на документацию PowerShell в качестве подтверждающего доказательства, но, увы, мой поиск был бесплодным. Если вы случайно знаете, где задокументировано разделение контекста, напишите комментарий здесь, чтобы сообщить мне об этом!)

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

Я создал invoke-async, который позволяет запускать несколько блоков скриптов / командлетов / функций одновременно. это отлично подходит для небольших заданий (сканирование подсети или запрос wmi против 100 машин), потому что накладные расходы на создание runspace против времени запуска start-job довольно радикальны. Его можно использовать так.

С сценария,

$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

просто командлет/функция

$servers = Get-Content servers.txt 

$rtn = Invoke-Async -Set $servers -SetParam computername -Params @{count=1} -Cmdlet Test-Connection -ThreadCount 50

фоновые задания дороги для настройки и не являются многоразовыми. PowerShell MVP Oisin Grehan имеет хороший пример многопоточности PowerShell http://www.nivot.org/2009/01/22/CTP3TheRunspaceFactoryAndPowerShellAccelerators.aspx

(сайт 10/25/2010 не работает):

i'e использовал адаптированный сценарий Oisin для использования в процедуре загрузки данных здесь:

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

для завершения предыдущих ответов, вы также можете использовать Wait-Job чтобы дождаться завершения всех заданий:

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