Task 和 async await 需要指导
Guidance needed with Task and async await
在浏览了很多文章和视频之后,我仍然遇到异步问题 programming.I 我正在处理一个项目,在该项目中,我在服务层中将所有方法创建为异步。所有 return Task <T>
或 Task
(我确保不会 return 作废)。
现在到这个问题。我的 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 的每个 'awaitable',它都使用自己的 DbContext
实例。
因此,请确保您没有使用 DbContext
单例;如果可以的话,在你去的时候实例化一个新的,或者像他在 link 中那样使用容器变得棘手(容器是你的朋友)
也许您应该在编写异步方法时使用此指南
指南:
按照编写常规方法的正常方式编写方法,然后将其转换为异步方法。
在方法声明中使用async关键字。
public async Task<int> ExampleMethodAsync()
{
// . . . .
}
在调用异步的代码中使用 await 关键字 process/method.
int resultValue = await ExampleMethodAsync();
注意:await只能用在async关键字修饰的async方法中。
在异步方法中使用正确的 return 类型之一以获得结果
return types for an async method need to be one of the following:
- 如果您的方法有一个 return 语句,其中操作数的类型为 TResult。
- 如果您的方法没有 return 语句或具有没有操作数的 return 语句,则执行任务。
- 如果您正在编写异步事件处理程序,则无效。
调用方法名末尾添加“Async”后缀。这不是必需的,但被考虑
在 C# 中编写异步方法的约定。
public async Task<int> ExampleCallingMethodAsync()
{
// . . . .
}
在异步方法代码中至少包含一个 await 表达式。
在 await 表达式中暂停异步方法不会
构成方法的出口,finally块不运行.
public async Task<int> ExampleMethodAsync()
{
//some code
string pageContents = await client.GetStringAsync(uri);
//some more code
return pageContents.Length;
}
注:
- 您必须调整您的异步方法 returning。 returned 的对象必须与异步方法
的类型 Task<T>
相匹配
- 如果异步方法不使用等待运算符来标记挂起点,则该方法
尽管有 async 修饰符,但仍像同步方法一样执行。编译器发出一个
此类方法的警告。
下面是转为异步方法的典型方法
例子
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);
}
希望对您有所帮助?
在浏览了很多文章和视频之后,我仍然遇到异步问题 programming.I 我正在处理一个项目,在该项目中,我在服务层中将所有方法创建为异步。所有 return Task <T>
或 Task
(我确保不会 return 作废)。
现在到这个问题。我的 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 的每个 'awaitable',它都使用自己的 DbContext
实例。
因此,请确保您没有使用 DbContext
单例;如果可以的话,在你去的时候实例化一个新的,或者像他在 link 中那样使用容器变得棘手(容器是你的朋友)
也许您应该在编写异步方法时使用此指南
指南:
按照编写常规方法的正常方式编写方法,然后将其转换为异步方法。
在方法声明中使用async关键字。
public async Task<int> ExampleMethodAsync() { // . . . . }
在调用异步的代码中使用 await 关键字 process/method.
int resultValue = await ExampleMethodAsync();
注意:await只能用在async关键字修饰的async方法中。
在异步方法中使用正确的 return 类型之一以获得结果
return types for an async method need to be one of the following:
- 如果您的方法有一个 return 语句,其中操作数的类型为 TResult。
- 如果您的方法没有 return 语句或具有没有操作数的 return 语句,则执行任务。
- 如果您正在编写异步事件处理程序,则无效。
调用方法名末尾添加“Async”后缀。这不是必需的,但被考虑 在 C# 中编写异步方法的约定。
public async Task<int> ExampleCallingMethodAsync() { // . . . . }
在异步方法代码中至少包含一个 await 表达式。 在 await 表达式中暂停异步方法不会 构成方法的出口,finally块不运行.
public async Task<int> ExampleMethodAsync() { //some code string pageContents = await client.GetStringAsync(uri); //some more code return pageContents.Length; }
注:
- 您必须调整您的异步方法 returning。 returned 的对象必须与异步方法 的类型
- 如果异步方法不使用等待运算符来标记挂起点,则该方法 尽管有 async 修饰符,但仍像同步方法一样执行。编译器发出一个 此类方法的警告。
Task<T>
相匹配
下面是转为异步方法的典型方法
例子
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);
}
希望对您有所帮助?