2010-10-25 3 views
94

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

Идеально Я хотел бы что-то вроде параллельного Еогеасп в .net 4.

что-то довольно, как аналоговый или цифровой:

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

Может быть, я бы лучше просто упасть вниз к C# ...

+0

** ТЛ; др: ** 'приемно-задание (ожидание-работа ($ а = запуск задания {«Heyo ! "})); remove-job $ a' или '$ a = start-job {" heyo!"}; wait-job $ a; receive-job $ a; remove-job $ a' Обратите внимание, что если вы вызываете' get-job' до завершения задания, вы можете ничего не получить. – Andrew

+0

Также '(get -job $ a) .jobstateinfo.state; ' – Andrew

ответ

71

Вы можете выполнять параллельные задания в Power ад 2 используя Background Jobs. Проверьте 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 
+3

Итак, я несколько раз пробовал это предложение, но кажется, что мои переменные не получают правильно. Для использования того же примера, когда эта строка выполняется:« Test-Path »\ \ $ _ \ c $ \ Something "' Я бы ожидал, что он расширит '$ _' в текущем элементе, но это не так. Вместо этого он возвращает пустое значение. Это, похоже, происходит изнутри блоков скриптов. Я пишу это значение сразу после первого комментария, кажется, что он работает правильно. – rjg

+1

@likwid - звучит как отдельный вопрос для сайта –

+0

Как просмотреть результаты работы, которое работает в фоновом режиме? – SimpleGuy

6

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

(10/25/2010 сайт вниз):

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

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

76

ответ от Стива Townsend правильно в теории, но не на практике, @likwid указал. В моем пересмотренном коде учтены барьер работы-контекста - нет пересечения этого барьера по умолчанию! Таким образом, автоматическая переменная $_ может использоваться в цикле, но не может использоваться непосредственно внутри блока сценария, поскольку она находится внутри отдельного контекста, созданного заданием.

Чтобы передать переменные из родительского контекста к контексту ребенка, используйте параметр -ArgumentList на 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 в качестве подтверждающих доказательств, но, увы, мои поиски были безрезультатными. Если вы не знаете, где разделение контекста документирована, оставить комментарий здесь, чтобы сообщить мне знаю!)

+0

Спасибо за этот ответ. Я попытался использовать ваше решение, но мне не удалось его полностью работать. Можете ли вы взглянуть на мой вопрос здесь: http://stackoverflow.com/questions/28509659/unzipping-works-on-singlethread-but-not-multithread –

+0

Альтернативно, довольно просто вызвать отдельный файл сценария. Просто используйте 'Start-Job -FilePath script.ps1 -ArgumentList $ _' –

7

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

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

с 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 

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

$servers = Get-Content servers.txt 

$rtn = Invoke-Async -Set $servers -SetParam computername -Params @{count=1} -Cmdlet Test-Connection -ThreadCount 50 
Смежные вопросы