【问题标题】:List<MyObject> does not contain a definition for GetAwaiterList<MyObject> 不包含 GetAwaiter 的定义
【发布时间】:2017-04-08 01:55:56
【问题描述】:

我有一个返回对象的 List 的方法。此方法需要一段时间才能运行。

private List<MyObject> GetBigList()
{
    ... slow stuff
}

从 4 或 5 个来源调用此方法。所以,我想我会尝试使用 async 和 await 来在这个列表构建时让事情继续进行。我添加了这个方法:

public async Task<List<MyObject>> GetBigListAsync()
{
    var resultsTask = GetBigList();
    var resuls = await resultsTask;
    return resuls;
}

但是,在这一行:

var resuls = await resultsTask;

我收到此错误:

List 不包含 GetAwaiter 的定义, 并且找不到接受 List 类型的第一个参数的扩展方法“GetAwaiter”。

我错过了什么?

【问题讨论】:

  • 您的示例代码没有显示在 GetBigList 方法中对 Task 的任何使用,也没有标记为异步,这意味着无法等待该方法的结果。
  • 尝试异步任务> GetBigList()
  • 记住,await 不会把同步操作变成异步操作。 Await 将当前方法的剩余部分注册为已经存在的异步操作的延续。 Await 是关于管理异步,而不是创建它。如果您希望同步操作是异步的,您将不得不想办法实现它。
  • I think This Link My Help You List.add() 异步任务等待正确的语法

标签: c# async-await


【解决方案1】:

几年后,但我觉得值得为该集合添加,一旦人们搜索分辨率,因为 .NET 已经发生了很大变化:

return await Task.FromResult(GetBigList())

【讨论】:

  • 这是最佳做法吗?
  • @JoBo 最佳实践?我认为这是一种很好的做法,因为它允许代码同步运行,但仍然适合异步范式。这将允许您以零碎的方式从同步执行转移到异步执行,这样更安全。
【解决方案2】:

看来您是异步等待的新手。真正帮助我理解 async-await 的作用是 Eric Lippert 在this interview. 中给出的餐厅类比@ 在中间某处搜索异步等待。

在这里,他描述了如果厨师必须等待某事,他不会什么都不做,而是开始四处张望,看看他是否可以在此期间做其他事情。

Async-await 类似。而不是等待读取文件,返回数据库查询,下载网页,您的线程将向上调用堆栈查看是否有任何调用者没有等待并执行这些语句,直到他看到等待。一旦他看到等待,线程就会再次向上调用堆栈,以查看是否有一个调用者没有等待等。一段时间后,当读取文件或查询完成等时,执行等待之后的语句。

通常在阅读您的大列表时,您的线程会非常忙碌,而不是无所事事地等待。不确定订购另一个线程来完成这些工作是否会缩短阅读列表所需的时间。考虑测量这两种方法。

使用 async-await 的一个原因,即使它会延长时间 需要阅读大列表,将保持调用者(用户 界面?)响应式。

要使您的函数异步,您应该执行以下操作:

  • 声明函数异步;
  • 而不是TResult,返回Task&lt;TResult&gt;,而不是void,返回Task
  • 如果您的函数调用其他异步函数,请考虑记住返回的任务而不是 await,做其他您需要做的有用的事情,并在需要结果时 await 任务;
  • 如果你真的想让另一个线程来做那些忙碌的事情。打电话

    Task.Run(() => GetBigList())

并在您需要结果时等待。

private async Task<List<MyObject>> GetBigListAsync()
{
    var myTask = Task.Run( () => GetBigList());
    // your thread is free to do other useful stuff right nw
    DoOtherUsefulStuff();
    // after a while you need the result, await for myTask:
    List<MyObject> result = await myTask;

    // you can now use the results of loading:
    ProcessResult(result);
    return result;
}

再说一次:如果您在其他线程正在加载列表时没有任何有用的事情可做(例如保持 UI 响应),请不要这样做,或者至少衡量您是否更快。

其他帮助我理解 async-await 的文章是 - Async await,由非常乐于助人的 Stephen Cleary, - 更高级一点:Async-Wait best practices.

【讨论】:

  • 你的例子同步工作!!!我检查了它。 Visual Studio 也差不多。该方法不是预期的,将同步执行。
【解决方案3】:

resultTask 只是从GetBigList() 返回的列表,所以那里不会发生任何异步事件。

您可以做的是使用Task.Run 将任务卸载到线程池上的单独线程并返回可等待的Task 对象:

// Bad code
public Task<List<MyObject>> GetBigListAsync()
{
    return Task.Run(() => GetBigList());
}

虽然上面的示例最符合您的尝试,但这并不是最佳实践。尝试使 GetBigList() 自然异步,或者如果真的没有办法,将在单独线程上执行代码的决定留给调用代码,并且不要在实现 F.e. 中隐藏它。如果调用代码已经异步运行,则没有理由再生成另一个线程。 This article 对此进行了更详细的描述。

【讨论】:

  • 所以宁可将实际方法设为 Task> GetBigListAsync() 然后使用 for var result = Task.FromResult(GetBigList())?
猜你喜欢
  • 2017-11-20
  • 2023-01-09
  • 1970-01-01
  • 2013-04-23
  • 2012-08-04
  • 2017-04-20
  • 2018-08-21
  • 2016-12-15
  • 1970-01-01
相关资源
最近更新 更多