c# - 如何从 Parallel.ForEach 循环内部抛出异常?

标签 c# foreach exception parallel-processing

我有一个 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
}

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

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

最佳答案

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

if (Interlocked.Increment(ref failedFiles) == 10)

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

关于c# - 如何从 Parallel.ForEach 循环内部抛出异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30649099/

相关文章:

C# 和 SQL 服务器 : deadlock in parallel transactions

php - foreach($ex as $k=>$v) 中的 $k => $v 是什么意思?

java - 使用 CompletableFuture 调整异常的正确方法

java - 可以抛出运行时异常?

ios - 以 Button 中类型为 NSException 的未捕获异常终止

C# 在新线程或任务中打开表单?

c# - Linq2Sql 数据上下文登录/注销行为

c# - 如何在 C# 中以像素级操作图像

php - 在插入新数据之前删除表数据

php foreach 每 100 次 sleep 然后继续