2016-10-07 2 views
1

가격 및 제품 세부 정보를 수집하기 위해 사이트를 구문 분석하려고합니다. 스크립트는 루프에서 작동하지만 속도는 매우 느립니다. 그래서 다중 스레드 powershell 스크립트를 작업으로 실행하려고합니다.Powershell - foreach가 배열로 작업 (로컬/멀티 스레드)

나는 많은 추천을 시도했지만 나는 마지막 10을 선택하고있어

(웹 요청 화면가 점멸) 나는 그것의 작업을 볼 수 있지만 밖으로 결과를 얻기 위해 사투를 벌인거야 그러나 나는 나중에 조절판에 넣을 것이다. 그냥 출력 할 수 없습니다. 본질적으로 모든 결과가 $ arr로 다시 흐르고 싶습니다.


#Import Danmurphy Sitelist 
[xml] $XmlDocument = (New-Object System.Net.WebClient).DownloadString("http://www.example.com/sites.xml") 

#get websites listed 
$ImportedProducts = $XmlDocument.DocumentElement.url | select -Last 10 

"Killing existing jobs . . ." 
Get-Job | Remove-Job -Force 
"Done." 

#loop through the products 

#Create Array 
$arr = @() 

#$argumentlist 

#ScriptBlock 
$ScriptBlock = { 
Param($product,$arr) 

if ($product.loc -like "http://www.example.com/product/*"){ 

$uri = $product.loc 
$WebResponse = Invoke-WebRequest -Uri $uri -SessionVariable WS 


#mainpricetest 
$mainprice = $WebResponse.AllElements | ? { $_.Class -eq 'price-main' } | select innerText 

$MainPriceArray = $mainprice.innerText.Split(' ') 

$MainUnitArry = $MainPriceArray[1..10] 

$MainDollar = $MainPriceArray[0] 

$MainUnit = $MainUnitArry -join ' ' 


$item = New-Object PSObject 
$item | Add-Member -type NoteProperty -Name 'Product Site' -Value $($product.loc) 
$item | Add-Member -type NoteProperty -Name 'Main Price' -Value $($MainDollar) 
$item | Add-Member -type NoteProperty -Name 'Main Unit' -Value $($MainUnit) 



$arr += $item 

} 
} 

foreach ($product in $ImportedProducts){ 
Start-Job -InputObject $ImportedProducts -ScriptBlock $ScriptBlock -ArgumentList $product,$arr 
} 

$data = Get-Job * | Receive-Job 

#Show Array 
$arr 
+0

왜 '$ arr + = $ item'을 스크립트 블록에서 제거하고'$ data'를 사용하여 출력을 캡처합니까? – Matt

답변

1

그래서 당신은 그것을 위해 실행 영역을 사용하고자하는 것입니다. Runspaces는 꽤 복잡한 일입니다. 다행히도 Posh-RSJob을 사용하면 모든 것을 처리 할 수 ​​있습니다. https://github.com/proxb/PoshRSJob

스크립트 블록을 전달할 수 있으므로 조정이 거의 필요하지 않습니다. 이 같은 아마 뭔가 : 당신이 $의 편곡으로 결과를 얻고 싶은 경우에 당신이해야 할 시도로

foreach ($product in $ImportedProducts){ 
    Start-RSJob -ScriptBlock $ScriptBlock 
} 
Get-RSjob | Receive-RSJob 
+0

나는이 작품을 채점하는데 좋은 인상을 받았지만 결과물을 얻지 못하고있다. 더 많은 데이터가 항상 False입니다. 필자는 Bill Hurt의 제안에 따라 write-output $ 항목을 추가하려고 시도했습니다. '시작 - RSJob -InputObject $ ImportedProducts -scriptblock $를 ScriptBlock -ArgumentList $ 제품 -Throtle' 및 '{ $ 편곡 + = GET-RSJob - 스테이트가 완료 않습니다 | Receive-RSJob } (Get-RSJob -State Running) ' –

+1

스크랩 그 것. RSJob은 파이프에만 사용해야합니다. 고마워요,이 일했습니다 : '$ ImportedProducts | foreach {시작 -RSJob -ScriptBlock $ ScriptBlock -ArgumentList $ _ -Throttle 10} do { $ arr + = Get-RSJob -State Completed | 수신 RSJob Get-RSJob -State 완료 됨 | Remove-RSJob } while (Get-RSJob -State Running) ' –

1

, 당신은 스크립트 블록 내에서 그것을 할 수 없습니다. 병렬로 실행되는 여러 스크립트 블록은 들어갈 가치가없는 추가 단계를 수행하지 않고 변수의 단일 복사본에 액세스 할 수 없습니다.

문제에 대한 대답은 각 스크립트 블록의 출력을 일반 출력으로 작성하는 것입니다. 이 출력은 Receive-Job을 사용하여 작업에서 결과를 가져올 때까지 버퍼링되어 단일 스레드 방식으로 $ arr 변수에 캡처합니다. 아래는 당신을 거기에서 가장 많이 얻을 수있는 대구입니다.

#Import Danmurphy Sitelist 
[xml] $XmlDocument = (New-Object System.Net.WebClient).DownloadString("http://www.example.com/sites.xml") 

#get websites listed 
$ImportedProducts = $XmlDocument.DocumentElement.url | select -Last 10 

"Killing existing jobs . . ." 
Get-Job | Remove-Job -Force 
"Done." 

#loop through the products 

#Create Array 
$arr = @() 

#$argumentlist 

#ScriptBlock 
$ScriptBlock = { 
    Param($product) 

    if ($product.loc -like "http://www.example.com/product/*"){ 

    $uri = $product.loc 
    $WebResponse = Invoke-WebRequest -Uri $uri -SessionVariable WS 


    #mainpricetest 
    $mainprice = $WebResponse.AllElements | ? { $_.Class -eq 'price-main' } | select innerText 

    $MainPriceArray = $mainprice.innerText.Split(' ') 

    $MainUnitArry = $MainPriceArray[1..10] 

    $MainDollar = $MainPriceArray[0] 

    $MainUnit = $MainUnitArry -join ' ' 


    $item = New-Object PSObject 
    $item | Add-Member -type NoteProperty -Name 'Product Site' -Value $($product.loc) 
    $item | Add-Member -type NoteProperty -Name 'Main Price' -Value $($MainDollar) 
    $item | Add-Member -type NoteProperty -Name 'Main Unit' -Value $($MainUnit) 



    Write-Output $item 

    } 
} 

foreach ($product in $ImportedProducts){ 
    Start-Job -InputObject $ImportedProducts -ScriptBlock $ScriptBlock -ArgumentList $product 
} 

do { 
    $arr += Get-Job -State Completed | Receive-Job -AutoRemoveJob 
} while (Get-Job -State Running) 

#Show Array 
$arr 
+0

치료해 주셔서 감사합니다! –