这个问题在这里已有答案:
经过大量文章和视频后,我仍然遇到异步编程问题。我正在开发一个项目,在服务层我已经创建了所有方法async。所有返回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里面我也在调用异步方法。
怎么做,什么是最佳做法?
我相信你遇到了here描述的线程安全问题。如果是这样,你需要确保对于进入EF的每个'等待',它使用自己的DbContext
实例。
所以,请确保你没有使用DbContext
单身人士;如果你可以或者像链接中那样容易使用容器(容器是你的朋友),你可以实例化一个新的
也许您应该在编写异步方法时使用此指南
指南:
public async Task<int> ExampleMethodAsync()
{
// . . . .
}
int resultValue = await ExampleMethodAsync();
注意:await只能在async关键字修改的异步方法中使用。
return types for an async method need to be one of the following:
如果您的方法有一个return语句,其中操作数的类型为TResult,则执行该任务。
如果您的方法没有return语句或者没有操作数的return语句,则执行该任务。
如果您正在编写异步事件处理程序,则无效。public async Task<int> ExampleCallingMethodAsync()
{
// . . . .
}
public async Task<int> ExampleMethodAsync()
{
//some code
string pageContents = await client.GetStringAsync(uri);
//some more code
return pageContents.Length;
}
注意:
您必须调整异步方法返回的内容。返回的对象必须与异步方法的类型Task<T>
匹配
如果异步方法不使用await运算符来标记挂起点,则该方法将作为同步方法执行,尽管存在异步修饰符。编译器会为此类方法发出警告。下面是转换为异步方法的典型方法
例
private void WebPage(string someURI)
{
WebClient webClient = new WebClient();
string pageContent = webClient.DownloadString(someURI);
Console.WriteLine(pageContent);
}
变成:
private async void WebPageAsync(string someURI)
{
WebClient webClient = new WebClient();
string pageContent = await webClient.DownloadStringTaskAsync(someURI);
Console.WriteLine(pageContent);
}
我希望这可以帮到你?