PLinq AsParallel异步异常使应用程序崩溃

时间:2018-07-30 17:30:54

标签: c# asp.net .net asp.net-core

我的问题是有关在Plinq下的 ForAll 方法中捕获异常

我试图同时设置最大线程数来运行任务。 使用 数不清的 .AsParallel() .WithDegreeOfParallelism(100) .ForAll(异步项目=>等待AsyncTask())

它可以工作,但是如果AsyncTask引发异常,则应用程序将崩溃。

我已经做了以下测试:

try
{
   IEnumerable<string> enumerable = new List<string> { "st", "st" };
   enumerable.AsParallel()
   .ForAll(async f =>
   {
      try
      {
          throw new Exception(); // Or await AsyncTask that throws this
      }
      catch (Exception e)
      {
          e.ToString(); **// This Exception is captured**
          throw e;
      }
   });
}
catch (Exception e) **// THIS IS NOT CAPTURED AND THE APP CRASHES**
{
   e.ToString();
}
  1. 我想了解原因
  2. 和其他实施方案

1 个答案:

答案 0 :(得分:1)

enumerable.AsParallel()。ForAll()对枚举的每个元素并行执行给定操作。由于给定操作本身是异步的,因此ForAll()不会等到所有操作完成后再进行操作。在这种情况下,在您的AsyncTask()方法引发异常之前,执行的代码将离开try..catch块。这可能导致未处理的异常,从而使您的应用程序崩溃。

不要紧,您尝试等待AsyncTask(),因为ForAll()会获得简单的Action,而不会等待AsyncTask()的结果。

一个可能的解决方案是为每个没有AsParallel()。ForEach()的元素启动AsyncTask,然后在try..catch中等待结果。

存储

Task or Task<T>

显示一个列表,您可以使用task.Exception属性检查是否有任何任务引发了异常。

您可以执行以下操作:

    private async Task DoSomethingAsync()
    {
        try
        {
            IEnumerable<string> enumerable = new List<string> { "st", "st" };

            // start all tasks and store them in an array
            var tasks = enumerable.Select(TaskAsync).ToArray();

            // do something more without waiting until all tasks above completed
            // ...


            // await all tasks
            var completionTask = Task.WhenAll(tasks);
            await completionTask;

            // handle task exception if any exists
            if (completionTask.Status == TaskStatus.Faulted)
            {
                foreach (var task in tasks)
                {
                    if (task.Exception != null)
                    {
                        // throw an exception or handle the exception, e.g. log the exceptions to file / database
                    }
                }
            }
        }
        catch (Exception e)
        {
            // handle your exception, e.g. write a log to file / database
        }
    }

    private Task TaskAsync(string item)
    {
        // Task.Delay() is just a placeholder
        // do some async stuff here, e.g. access web services or a database
        return Task.Delay(10000);
    }