问题描述
我想处理大量 URL 并获取 *.jpg 文件位置。
问题是第二个 foreach 中的 $entry
不是线程安全的。
该脚本引发了数百个错误,因为 $entry
被一遍又一遍地覆盖。
当我将内部 foreach
移到 ForEach-Object
之外时,它工作正常但速度很慢。
如何在我的 ForEach-Object
中正确处理拆分输出而不会出现这些错误?
-
$array
只包含大量网址 -
$clean_img_array
是操作的输出数组 -
$tmpArray
是对$clean_img_array
的引用,以便在并行 ForEach 中使用它
错误:
InvalidOperation:
Line |
14 | [void]$tmpArray:clean_img_array.Add($entry);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| You cannot call a method on a null-valued expression.
片段:
$clean_img_array = [System.Collections.ArrayList]@();
$array | ForEach-Object -Parallel {
$web = Invoke-RestMethod $_;
$i=1;
foreach($entry in $web.Split("`"")){
echo $entry;
if($entry.IndexOf(".jpg") -ne -1 -And $entry.IndexOf("http") -ne -1){
if($entry.IndexOf("?") -ne -1){
$tmpArray = $using:clean_img_array;
[void]$tmpArray.Add($entry.Substring(0,$entry.IndexOf('?')));
}else{
$tmpArray = $using:Clean_img_array;
[void]$tmpArray:clean_img_array.Add($entry);
}
}
}
} -ThrottleLimit 20
解决方法
这是一个简单的例子。 $a 和 $b 都是数组。 $b 是并行循环的结果。就像文档中的 example 12。
$a = 1..10
$b = $a | foreach-object -parallel { $_ + 1 }
$b
2
3
4
5
6
7
8
9
10
11
,
感谢支持!
我将@js2012 的答案与我自己的答案结合起来。
仅返回并不能解决 $entry
的线程取消保存行为,但清楚地解开了工作流程。
但是我使用了内联版本的 .foreach
和管道变量 $_
在我看来是线程安全的。现在运行速度非常快,超过 200 万个条目。
-
$array
保存要处理的网址 -
$clean_img_array
返回抓取的图片网址$clean_img_array = $array | ForEach-Object -Parallel { $web = Invoke-RestMethod $_; $web.Split("`"").foreach({ if($_ -ne $null){ if($_.IndexOf(".jpg") -ne -1 -And $_.IndexOf("http") -ne -1){ if($_.IndexOf("?") -ne -1){ return $_.Substring(0,$entry.IndexOf('?')); }else{ return $_; } } } }); } -ThrottleLimit 25