如何从Parallel.ForEach循环中抛出异常?

use*_*er1 2 c# parallel-processing foreach exception-handling

我有一个Parallel.Foreach下载文件的循环:

try
{
     var parallelOptions = new ParallelOptions();
     parallelOptions.MaxDegreeOfParallelism = 8;
     int failedFiles = 0;
     Parallel.ForEach(FilesToDownload, parallelOptions, tile =>
     {
         bool downloaded = DownloadTile(File);
         if (downloaded)
         {
              //Downloaded :)
         }
         else
         {
               failedFiles++;
               if (failedFiles > 10)
               {
                   throw new Exception("10 Files Failed to download. Failing download");
               }
          } 
          parallelOptions.CancellationToken.ThrowIfCancellationRequested();
      });
}
catch (Exception ex)
{
    throw; //This throws it up to a main method that cancels my program
}
Run Code Online (Sandbox Code Playgroud)

我想知道ExceptionParallel.Foreach方法内部抛出一个正确的方法是什么?在我的实例中,我认为一旦抛出第一个异常,我将看到抛出异常8次.

Parallel.ForEach循环中抛出异常的正确方法是什么?

Vik*_*ler 5

首先,更好地使用Interlocked.Increment(ref failedFiles)而不是failedFiles++.否则可能会发生10-15次失败,但由于缺少缓存同步和编译器/抖动优化的影响,最终会得到一个值为7-8的计数器.您的程序循环可能会抛出更多异常,但最后它将聚合为一个异常AggregateException,并且outter catch()将接收该单个异常实例.如果您不想要更多例外,则AggregateException可以使用==而不是>

if (Interlocked.Increment(ref failedFiles) == 10)
Run Code Online (Sandbox Code Playgroud)

当在循环内抛出异常,Parallel.ForEach阻止其他迭代启动时,它等待当前正在运行的迭代完成,然后它聚合它捕获的所有异常,将其打包AggregateException并抛出该单个实例.这意味着在您的情况下,单个例外将阻止进一步下载.