以下是我在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将始终为空?
我意识到我正在和鲨鱼游泳,使用这种多线程的力量而不完全了解它的含义。因此问题!感谢。
答案 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
。