Powershell - foreach 到数组作为作业(本地/多线程)
Powershell - foreach to array as job (local / multi-threaded)
我正在尝试解析网站以收集价格和产品详细信息。该脚本循环运行,但速度非常慢。所以我正在尝试 运行 一个多线程 powershell 脚本作为一项工作。
我已经尝试了很多建议,但即使我可以看到它的工作(网络请求屏幕闪烁),我也很难得到结果
我只选择最后 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
所以你会想为此使用运行空间。 Runspaces 是一件相当复杂的事情,幸运的是我们有 Posh-RSJob 可以为你处理一切。 https://github.com/proxb/PoshRSJob
您可以传入脚本块,因此只需很少的调整。
大概是这样的:
foreach ($product in $ImportedProducts){
Start-RSJob -ScriptBlock $ScriptBlock
}
Get-RSjob | Receive-RSJob
如果您想将结果存入 $arr,则不能像您尝试的那样从脚本块中进行操作。不允许多个脚本块 运行 并行访问一个变量的单个副本而不采取不值得进入的额外步骤。
您的问题的答案是将每个脚本块的输出写为常规输出。该输出会被缓冲,直到您使用 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
我正在尝试解析网站以收集价格和产品详细信息。该脚本循环运行,但速度非常慢。所以我正在尝试 运行 一个多线程 powershell 脚本作为一项工作。
我已经尝试了很多建议,但即使我可以看到它的工作(网络请求屏幕闪烁),我也很难得到结果
我只选择最后 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
所以你会想为此使用运行空间。 Runspaces 是一件相当复杂的事情,幸运的是我们有 Posh-RSJob 可以为你处理一切。 https://github.com/proxb/PoshRSJob
您可以传入脚本块,因此只需很少的调整。 大概是这样的:
foreach ($product in $ImportedProducts){
Start-RSJob -ScriptBlock $ScriptBlock
}
Get-RSjob | Receive-RSJob
如果您想将结果存入 $arr,则不能像您尝试的那样从脚本块中进行操作。不允许多个脚本块 运行 并行访问一个变量的单个副本而不采取不值得进入的额外步骤。
您的问题的答案是将每个脚本块的输出写为常规输出。该输出会被缓冲,直到您使用 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