【问题标题】:async await returning Task<List<T>> instead of List<T> on calling aync method异步等待在调用异步方法时返回 Task<List<T>> 而不是 List<T>
【发布时间】:2015-02-12 18:06:48
【问题描述】:

我正在尝试了解 async await 的用法,我研究了几篇博客文章,现在我制作了一个测试代码,但它并没有按照我期望的方式工作。

我有一个返回列表的方法:

private List<Employee> GetEmployees()
{

 IList<Employee> list = new List<Employee>();
 list.Add(new Employee() { Id = 1, Age = 20, Name = "Kavin" });
 list.Add(new Employee() { Id = 2, Age = 30, Name = "Alen" });
 list.Add(new Employee() { Id = 3, Age = 20, Name = "Suresh" });
 list.Add(new Employee() { Id = 4, Age = 30, Name = "Jay" });
 list.Add(new Employee() { Id = 5, Age = 20, Name = "Nanda" });
 list.Add(new Employee() { Id = 5, Age = 20, Name = "Kavin" });
 list.Add(new Employee() { Id = 5, Age = 20, Name = "Kavin" });
 list.Add(new Employee() { Id = 1, Age = 23, Name = "Test" });

 return list;
}

然后我写了我的异步方法:

private async Task<List<Employee>> TestEmployeesGetAsync()
{

  var result = await Task.Run(() => GetEmployees());

  return result;
}

当我调用这个方法时:

var Result = TestEmployeesGetAsync();

视觉工作室告诉我它返回Task&lt;List&lt;T&gt;&gt;,它的用法是:

List<Employee> result = await TestEmployeesGetAsync();

为什么我需要把 await 放在调用方法上,如果我放 await 它当然会产生编译器错误,因为 await 也应该有异步。有人可以清除我的想法如何调用它,以便我可以得到List&lt;T&gt;而不是Task&lt;List&lt;T&gt;&gt;

【问题讨论】:

标签: c# .net asynchronous task-parallel-library async-await


【解决方案1】:

为什么我需要在调用方法上加上等待,如果我把它给了 编译器错误当然是因为 await 也应该有异步。

编译器需要一些依赖项,以便了解您正在运行异步方法。信号是方法声明上的async 修饰符。将其标记为async 后,您可以使用await 关键字。这就是为什么 async 在调用堆栈中“一直”传播的原因,因为当您调用一个 async 方法并需要等待其结果时,您需要使用 async 修饰符标记使用方法。

为了使您的方法有效,您需要执行以下操作:

public async Task GetEmployeesAsync()
{
   List<Employees> result = await TestEmployeesGetAsync();
}

附带说明,请注意you should not expose async wrappers over sync methods

【讨论】:

  • 你的意思是如果不将它包装在另一个异步方法中,我就不能调用它?
  • 99% 的时间,这就是您应该调用异步代码的方式。
【解决方案2】:

你基本上需要等待TestEmployeesGetAsync返回的任务结果。您可以使用await 异步执行此操作,它将结果为您解包到List&lt;Employee&gt;,或者您可以使用Result 属性从任务中获取结果。不过这可以cause a deadlock,所以你需要小心。

使用async-await,它往往会沿着调用链向上,即等待async 方法需要您在另一个async 方法中执行此操作(正如您所发现的那样),并且等待该方法需要您在另一个async 方法中,因此async 方法在代码库中传播,直到您到达事件处理程序或Main(不能标记为async)。

async 方法的这种扩散并不罕见,为了避免这种情况,您可以使用 Task.WaitTask.Result 等待任务完成,但这些是阻塞方法,可能导致上述死锁。它也是一种称为同步优于异步的反模式,它违背了异步执行工作的目的,因为无论如何你最终都会阻塞等待它完成。

正如@BenVoigt 所指出的,一个例外是当您启动多个异步请求,然后使用Task.WaitAll 阻止等待所有任务完成时。

【讨论】:

  • 它并没有完全破坏目的,因为您仍然可以在等待期间发生多个异步操作。例如,使用Task.WaitAll
  • 我会扩展“它倾向于在调用链中向上”。如果你还不知道那是什么意思,那这句话就很难理解了。
猜你喜欢
  • 1970-01-01
  • 2019-12-18
  • 2014-11-29
  • 1970-01-01
  • 2017-06-04
  • 2022-06-21
  • 1970-01-01
相关资源
最近更新 更多