我们目前正在重构我们项目的各个部分上下异步,是的!
由于我们的理解不同,我和同事(让我们称他为吉姆)对于我们的异步/等待代码将如何执行以及编写它的方式有不同的看法.
以下是Jim写的示例方法:
public async Task<HouseModel> GetHouseModel(Guid houseId)
{
House house = await _houseService.GetHouse(houseId);
Task<IEnumerable<Furniture>> furniture = _furnitureService.GetFurnitureForHouse(house);
Task<IEnumerable<Appliances>> appliances = _applianceService.GetAppliancesForHouse(house);
return _houseModelFactory.MakeHouseModel(await furniture, await appliances);
}
Run Code Online (Sandbox Code Playgroud)
以及如何编写它的示例:
public async Task<HouseModel> GetHouseModel(Guid houseId)
{
House house = await _houseService.GetHouse(houseId);
IEnumerable<Furniture> furniture = await _furnitureService.GetFurnitureForHouse(house);
IEnumerable<Appliances> appliances = await _applianceService.GetAppliancesForHouse(house);
return _houseModelFactory.MakeHouseModel(furniture, appliances);
}
Run Code Online (Sandbox Code Playgroud)
我的理解是:因为上面的服务furniture和appliance服务中的方法都需要House,所以House在继续之前它们会等待可用.然后,两个需要的方法House都会运行,但第二个方法(GetAppliancesForHouse)不会等到第一个方法在开始之前完成.
吉姆的理解是:我们应该只在需要时才等待这两种方法.这样他们就会彼此平行.他认为按照我的方式做,将导致第二种方法等待第一种方法,即:GetAppliancesForHouse等待GetFurnitureForHouse.
这些理解中的任何一个是否正确?或者我们一直在进行弥补?我们何时应该等待?
等待故障任务(具有异常集的任务)时,await将重新抛出存储的异常.如果存储的异常是a AggregateException,它将重新抛出第一个并丢弃其余的异常.
我们如何使用await并同时抛出原件AggregateException以便我们不会意外丢失错误信息?
注意,当然可以考虑使用hacky解决方案(例如,试一试await,然后调用Task.Wait).我真的希望找到一个干净的解决方案.这里最好的做法是什么?
我想过使用自定义awaiter,但内置TaskAwaiter包含很多魔法,我不知道如何完全重现.它调用TPL类型的内部API.我也不想重现所有这些.
如果你想玩它,这是一个简短的repro:
static void Main()
{
Run().Wait();
}
static async Task Run()
{
Task[] tasks = new[] { CreateTask("ex1"), CreateTask("ex2") };
await Task.WhenAll(tasks);
}
static Task CreateTask(string message)
{
return Task.Factory.StartNew(() => { throw new Exception(message); });
}
Run Code Online (Sandbox Code Playgroud)
只抛出两个例外中的一个Run.
请注意,Stack Overflow上的其他问题无法解决此特定问题.建议重复时请小心.
我的应用程序有时会停留在下面的代码中,并不总是有时候.
所有3种方法CalcQuarterlyFigures,CalcWeeklyFigures并CalcMonthlyFigures返回Task<List<MyClass>>.
注意,这在foreach循环内部运行.
List<Task> TaskList = new List<Task>();
if(i.DoCalculateAllHistory) {
var quarterly = CalcQuarterlyFigures(QuarterlyPrices, i.SeriesID);
TaskList.Add(quarterly);
var weekly = CalcWeeklyFigures(WeeklyPrices, i.SeriesID);
TaskList.Add(weekly);
var monthly = CalcMonthlyFigures(MonthlyPrice, i.SeriesID);
TaskList.Add(monthly);
Task.WaitAll(TaskList.ToArray());
if(monthly.Result.Count > 0)
monthlyPerfFig.AddRange(monthly.Result);
if(weekly.Result.Count > 0)
weeklyPerfFig.AddRange(weekly.Result);
if(quarterly.Result.Count > 0)
quartPerfFig.AddRange(quarterly.Result);
} else {
monthlyPerfFig.AddRange(await CalcMonthlyFigures(MonthlyPrice, i.SeriesID));
}
Run Code Online (Sandbox Code Playgroud)
我在这里错过任何导致死锁的东西吗?