我的MVC应用程序偶尔导致死锁。我认为这可能是由于我从完成的异步任务中收集数据的错误方式。
我有两个独立的异步方法。
// here I already know that both tasks are completed and
// I am using (or abusing?) await to get task results
List<string> names1 = await task1.ConfigureAwait(false);
List<string> names2 = await task2.ConfigureAwait(false);
if (names1 != null) total.AddRange(names1);
if (names2 != null) total.AddRange(names2);
问题第1部分:从这些任务中收集结果的最安全的推荐方法和最佳做法是什么:
total.AddRange(task1.IsFaulted ? new List<string> : task1.Result);
total.AddRange(task2.IsFaulted ? new List<string> : task2.Result);
或
var task1 = GetNamesFromSource1Async().ContinueWith(t =>
{
if ( !t.IsFaulted && t.Result != null)
{
return t.Result.Take(1).ToList();
}
});
问题第2部分:另外如果我想从第一个源转换数据,使用ContinueWith是否安全(当我说安全时我的意思是从死锁的角度来看)
{{1}}
备注:这里我通过检查IsFaulted标志来尝试控制每个任务中的异常。
对于解决此问题的最佳做法的建议将受到高度赞赏。我使用的是.NET 4.5
答案 0 :(得分:3)
.Result
是一个阻塞调用,当与async / await混合时会导致死锁
var task1 = GetNamesFromSource1Async(); // a database call, may throw an exception
var task2 = GetNamesFromSource2Async(); // a database call, may throw an exception
var total = new List<string>();
var results = await Task.WhenAll(task1, task2);
total.AddRange(results.Where(s => s != null && s.Count > 0).SelectMany(s => s));
<强>更新强>
以上假设返回类型都是相同的。
但是从你的评论......
如果我仍然需要收集结果,您将如何修改最后一行? 但是task1和task2是基于不同的类型吗?
并参考此答案
Awaiting multiple Tasks with different results
然后它将被修改为
var task1 = GetNamesFromSource1Async(); // a database call, may throw an exception
var task2 = GetNamesFromSource2Async(); // a database call, may throw an exception
var total = new List<string>();
await Task.WhenAll(task1, task2);
List<String> names1 = await task1;
List<int> names2 = await task2;
//...process results