Можно ли конвертировать ForEach-Objects в Jobs? - PullRequest
1 голос
/ 24 октября 2019

У меня есть скрипт powershell, который преобразует данные CSV в XML. В файле CSV около 11 тыс. Строк. Процесс в моем скрипте занимает около 3-5 минут, чтобы преобразовать все строки в строку XML, и компьютер использует только 30% процессорного времени. Есть ли более эффективный способ сделать это? Я провел некоторое исследование в Google, и я продолжаю читать о рабочих местах, но я не понимаю, как их использовать или если это будет работать для меня.

Я проверил сродство и приоритет, и при установке его на самые высокие уровни производительности не изменилось.

Вывод отформатирован так, как мне нужно для загружаемой системыв. Поэтому в идеале я не хочу менять вывод только зацикливание секций.

$OrderFile = "FileLocation.csv"
$OutputXML = "OutputFileLocation.xml"
$OrderData = Import-Csv -path $OrderFile

#Create a string template for the file and map fields for data.
$TemplateOuter = @'
<service_orders>$($xml)</service_orders>
'@

$TemplateCust = @'
<service_order><account_name></account_name><route_group></route_group><order_number>$($item.order_num)</order_number><delivery_type>$($item.delivery_type)</delivery_type><customer_code>$($item.customer_code)</customer_code><delivery_date>$($item.delivery_date)</delivery_date><cod>$($item.cod)</cod><service_time></service_time><note></note><line_items>$($items)</line_items></service_order>
'@

$TemplateItems = @'
<line_item><serial_number>$($item.sku)</serial_number><quantity>$($item.quantity)</quantity><amount>$($item.amount)</amount><description>$($item.description)</description><item_sequence></item_sequence><line_item_notes></line_item_notes><line_taxes>$($item.line_taxes)</line_taxes><line_amount></line_amount><category_name>$($item.category_name)</category_name><size_1>$($item.size_1)</size_1><size_2>$($item.size_2)</size_2><size_3>$($item.size_3)</size_3></line_item>
'@

#Loop through each of the orders and expand the order templates
$xml = $OrderData | Group-Object order_num -ov grp | ForEach-Object { 
            $items = foreach ($item in $_.Group) {
                $ExecutionContext.InvokeCommand.ExpandString($TemplateItems)
            }
        $ExecutionContext.InvokeCommand.ExpandString($TemplateCust)
        } | foreach {$_ -replace '&', '+'}

$xml = $ExecutionContext.InvokeCommand.ExpandString($TemplateOuter)

#Create the XML File
$xml |Out-File $OutputXML

$OrdersXML = Get-Content $OutputXML
$Utf8NoBomEncoding  = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllLines($OutputXML, $OrdersXML, $Utf8NoBomEncoding)

Мой вывод получается так, как ожидалось для моих нужд, но, как я уже говорил, загрузка ЦП максимально увеличена на 30% только с 1 из 4используемых ядер, и процесс занимает около 3-5 минут для 11k строк.

11/1/2019 Итак, я попробовал следующее

$xml = $OrderData | Group-Object order_num -ov grp
$xml= ForEach-Object { 
                        Start-Job -Name $_.Group -ScriptBlock {
                            $items = foreach ($item in $xml.Group) 
                            {
                                $ExecutionContext.InvokeCommand.ExpandString($TemplateItems)
                            }
                            $ExecutionContext.InvokeCommand.ExpandString($TemplateCust) | foreach {$_ -replace '&', '+'} 
                            } -ArgumentList $_.Group
               }

И я вижу работу, и она заявляетэто имеет больше данных = правда, но когда я получаю работу, там ничего нет ....

1 Ответ

0 голосов
/ 26 октября 2019

Вот пример того, как вы можете обрабатывать данные параллельно с заданиями в фоновом режиме.

[System.Int16]$MaxRunningJobs = 10 #How many jobs should run at the same time
[System.Collections.ArrayList]$JobsToDo = @(1..20) #The input for the jobs --> data to process
[System.String[]]$JobOutput = @() #Output from the jobs

#This script will run inside the job and takes some input to process
[System.Management.Automation.ScriptBlock]$WorkToDo = {
    param
    (
        [System.Int16]$JobInput
    )

    #Do your work
    Start-Sleep -Seconds (Get-Random -Minimum 1 -Maximum 10)

    #Return output
    return ('Job ' + $JobInput + ' finished!')
}

#Process each job from the JobsToDo ArrayList and waits until every job is Completed & removed
while (($JobsToDo) -or (Get-Job))
{
    #Start jobs
    while (($JobsToDo) -and ((Get-Job -State Running).Count -lt $MaxRunningJobs))
    {
        #Start new job
        Start-Job -ScriptBlock $WorkToDo -ArgumentList $JobsToDo

        #Remove started job from job list
        $JobsToDo.Remove($JobsToDo[0])
    }

    #Receive jobs
    foreach ($CompletedJob in (Get-Job -State Completed))
    {
        #Receive job output
        $JobOutput += Receive-Job -Job $CompletedJob

        #Remove job
        Remove-Job -Job $CompletedJob
    }
}

#Show job output
$JobOutput
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...