在 Powershell 中正确使用 ForEach -parallel?

问题描述

我想处理大量 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