【问题标题】:What is the order of evaluation in a PLINQ query?PLINQ 查询中的求值顺序是什么?
【发布时间】:2016-02-09 14:46:37
【问题描述】:

以下是我在 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&lt;EmailToSend, Task&lt;SendMailResult&gt;&gt; 中引发异常(最有可能在调用 MailHelper.SendMailAsync() 时),那么 AggregateException 处理程序将被调用 - 以下 .ToList()是否在任何时候被调用过?

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

我意识到我正在使用这种多线程功能与鲨鱼一起游泳,而没有完全了解它的含义。因此问题!谢谢。

【问题讨论】:

    标签: c# .net multithreading plinq


    【解决方案1】:

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

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

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

    【讨论】:

    • 有趣!所以保证,在执行上面的代码之后,resultList 将是一个任务列表,在 Count 上等于 emailsToSend IEnumerable?
    • 是的。因为只有在Task.WaitAll 调用时才会抛出异常。它将在创建列表后调用,因此列表将具有预期的长度。
    • 因此,任何进一步的处理都应该检查以下内容:resultList.Where(t=&gt;t.IsFaulted==false).Select(t=&gt;t.Result).Where(...,对吧?
    • 如果您不关心失败的结果,那么可以。
    • 太棒了,谢谢。如果这个问题在 24 小时内没有得到更深入的答案,您的答案将被接受。
    猜你喜欢
    • 2019-06-16
    • 2022-12-06
    • 1970-01-01
    • 1970-01-01
    • 2019-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多