【发布时间】:2018-06-01 09:25:27
【问题描述】:
在浏览了很多文章和视频后,我仍然对异步编程有疑问。我正在做一个项目,在服务层中,我将所有方法都创建为异步。所有返回Task <T> 或Task(我确保不返回无效)。
现在到了这个问题。我的 Api 调用异步方法,这些方法在内部调用其他异步方法,甚至可能调用其他异步方法。所以每次遇到异步方法时我都在等待。
我认为这种方法的缺点是因为每次遇到异步时我都在等待结果,这将花费很多时间。例如:
public async Task<xyz> DoMainTask(int ActionId, int ItemId, int UserId)
{
await DoTask1(ActionId,ItemId,UserId); 3 sec
await DoTask2(ActionId,ItemId,UserId); 3 sec
await DoTask3(ActionId,ItemId,UserId); 3 sec
}
所以我不想等待 9 秒,因为这里的所有任务都是相互独立的。 我想做类似的事情:
public async Task<xyz> DoMainTask(int ActionId, int ItemId, int UserId)
{
List<Task> lst = new List<Task>();
t1= DoTask1(ActionId,ItemId,UserId);
lst.Add(t1);
t2 = DoTask2(ActionId,ItemId,UserId);
lst.Add(t2);
t3 = DoTask3(ActionId,ItemId,UserId);
lst.Add(t3);
await Task.WhenAll(lst);
// do some work
return xyz;
}
这可能需要大约 5-6 秒。我该怎么做呢? 每当我尝试使用第二种方法时,它都会出错:
在前一个异步操作完成之前在此上下文上启动了第二个操作
DoTask1 定义为:
public async Task DoTask1 (int ActionId, int ItemId, int UserId)
{
try
{
DailyActivityPoint dailyActivityPoint = new DailyActivityPoint()
{
ActionId = ActionId,
CreatedDate = DateTime.Now,
ItemId = ItemId,
UserId = UserId,
PointsAccumulated = await GetPointsAwardedForAction(ActionId)
};
_entities.DailyActivityPoints.Add(dailyActivityPoint);
await _entities.SaveChangesAsync();
}
catch (Exception ex)
{
}
}
在 DoTask1 内部,我也在调用异步方法。
如何做到这一点,最佳做法是什么?
【问题讨论】:
-
对 I/O 等非 cpu 绑定的东西使用 async/await,对更大/更长的计算等 cpu 绑定的东西使用线程。
-
我现在无法启动我的 Visual Studio 来帮助你,但一定要在
Task.WhenAll前面放一个 await -
我做了。忘记放在这里:p我会编辑帖子。
-
您的问题是您不能在多个任务中重用实体框架。您需要为每个任务创建一个新的 dbcontext。见stackoverflow.com/questions/36036401/…
-
是的。我正在使用 EF 开发一个 WebAPI2 项目。您分享的文章中给出的解决方案是解决用户使用 IOC 的问题。我不是。至少在这个模块中没有。没有为 DbContext 创建接口,仅用于我创建的服务。尽管我在属于同一项目的不同模块中使用了 autofac,但不认为它会以任何方式影响它。我是否需要将我的子方法创建为 Task
insted of async Task .
标签: c# entity-framework async-await task-parallel-library