List <MyObject>不包含GetAwaiter的定义

Cas*_*ton 9 c# async-await

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

private List<MyObject> GetBigList()
{
    ... slow stuff
}
Run Code Online (Sandbox Code Playgroud)

从4或5个来源调用此方法.所以,我想我会尝试使用async并等待在此列表构建时保持移动.我添加了这个方法:

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

但是,在这一行:

var resuls = await resultsTask;
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

List <MyObject>不包含GetAwaiter的定义,并且找不到接受类型为List <MyObject>的第一个参数的扩展方法'GetAwaiter'.

我错过了什么?

Har*_*lse 22

看来你是async-await的新手.真正帮助我理解async-await做什么的是Eric Lippert在这次采访中给出的餐厅类比.在中间某处搜索异步等待.

在这里,他描述如果厨师必须等待某事,而不是什么也不做,他开始环顾四周,看看他是否可以在此期间做其他事情.

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

通常在阅读您的大清单时,您的线程将非常繁忙,而不是空闲等待.不确定订购另一个线程来完成这些工作会增加读取列表所需的时间.考虑测量两种方法.

使用async-await的一个原因是,即使它会延长读取大列表所需的时间,也会使调用者(用户界面?)保持响应.

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

  • 声明函数异步;
  • 而不是TResult返回Task<TResult>而不是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;
}
Run Code Online (Sandbox Code Playgroud)

再一次:如果你在其他线程加载List时没有什么有用的东西(比如保持UI响应),不要这样做,或者至少衡量你是否更快.

其他帮助我理解async-await的文章是 - Async等待,由那么有用的Stephen Cleary,以及更高级的:Async-Wait最佳实践.


huy*_*itw 12

resultTask只是返回的列表GetBigList(),所以在那里什么都不会发生异步.

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

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

虽然上面的示例最符合您的尝试,但这不是最佳做法.尝试GetBigList()本质上是异步的,或者如果真的没有办法,请将关于在单独的线程上执行代码的决定留给调用代码,如果调用代码已经运行异步,则不要在实现Fe中隐藏它,有没有理由产生另一个线程.本文将更详细地介绍这一点.


cpo*_*ign 11

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

return await Task.FromResult(GetBigList())