PLINQ查询中的评估顺序是什么?

时间:2016-02-09 14:46:37

标签: c# .net multithreading plinq

以下是我在Windows服务中定期运行的PLINQ查询示例:

var resultList = new List<Task<SendMailResult>>();

try
{
    resultList = emailsToSend
        .AsParallel().WithDegreeOfParallelism(10)
        .Select(async e =>
        {
            bool bSuccess = false;

            if (await MailHelper.SendMailAsync(e.sTo, e.sSubject, e.sHTML) == true)
            {
                bSuccess = true;
            }

            return new SendMailResult
            {
                succeeded = bSuccess,
                resultid = e.id
            };
        }).ToList();

    Task.WaitAll(resultList.ToArray());
}
catch (AggregateException aggEx)
{
    foreach (var ex in aggEx.InnerExceptions)
        Console.Out.WriteLine(ex.Message);
}

我的问题是 - 如果在内部匿名async Func<EmailToSend, Task<SendMailResult>>中抛出异常(最有可能调用MailHelper.SendMailAsync()),那么将调用AggregateException处理程序 - 将以下{ {1}}在任何时候都被调用了?

换句话说,是否有可能某些任务成功完成,直到一个没有完成,并且在被捕获到AggregateException处理程序之后遵循下面的代码片段,我可能有一个非0计数的resultList?或者,一个异常是否意味着永远不会调用ToList(),如果抛出异常,resultList将始终为空?

我意识到我正在和鲨鱼游泳,使用这种多线程的力量而不完全了解它的含义。因此问题!感谢。

1 个答案:

答案 0 :(得分:1)

由于.ToList() laziness

Select会在任何时候被调用,结果列表将包含所有任务。
执行将以.ToList()方法调用开始。 Select只会提供可以列举的IEnumerable列表 如果某些任务因异常而失败,您将捕获它们,毕竟您将获得任务列表,其中某些任务将具有Faulted状态。

修改
异常抛出将由Task.WaitAll方法调用触发,因此将在之前创建列表,并将精确项目计为初始集合。

<强>更新
关于Task.WaitAll内部结构:
如果您想知道它是如何工作的,您可以查看source code 首先,collects all incompleted tasks然后waits完成这些任务 然后从所有任务中collects all inner exceptions,然后将其提升为单AggregateException