我有一个返回List<>的方法一个对象。此方法需要一段时间才能运行。
private List<MyObject> GetBigList()
{
... slow stuff
}
此方法从4个或5个来源调用。所以,我想我会尝试使用async并等待在此列表构建时保持移动。我添加了这个方法:
public async Task<List<MyObject>> GetBigListAsync()
{
var resultsTask = GetBigList();
var resuls = await resultsTask;
return resuls;
}
但是,在这一行:
var resuls = await resultsTask;
我收到此错误:
列表与LT;为MyObject&GT;不包含GetAwaiter的定义, 没有扩展方法'GetAwaiter'接受List&lt; MyObject&gt;类型的第一个参数可以找到。
我错过了什么?
答案 0 :(得分:19)
您似乎是异步等待的新手。真正帮助我理解async-await做什么的是Eric Lippert在this interview.搜索中间的某个地方进行异步等待的餐馆比喻。
在这里,他描述如果厨师必须等待某事,而不是什么都不做,他开始环顾四周,看看他是否可以在此期间做其他事情。
Async-await类似。而不是等待要读取的文件,要返回的数据库查询,要下载的网页,您的线程将在调用堆栈上查看是否有任何调用者没有等待并执行这些语句,直到他看到等待。一旦他看到await,线程再次上调调用堆栈以查看其中一个调用者是否在等待等等。在读取文件或查询完成等一段时间后,执行await之后的语句。 / p>
正常情况下,在阅读你的大清单时,你的线程会很忙,而不是空闲等待。不确定订购另一个线程来完成这些工作会增加读取列表所需的时间。考虑测量两种方法。
使用async-await的一个原因,即使它会延长时间 需要阅读大名单,将是保持呼叫者(用户 界面?)响应。
要使您的函数异步,您应该执行以下操作:
TResult
返回Task<TResult>
而不是void
返回Task
; await
,执行其他有用的操作,并在需要时执行await
任务; 如果你真的想让另一个线程做忙碌的事情。呼叫
Task.Run(()=&gt; 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;
}
再一次:如果你在另一个线程加载List时没有任何有用的事情(比如保持UI响应),不要这样做,或者至少衡量你是否更快。
帮助我理解async-await的其他文章是 - Async await,由有用的Stephen Cleary, - 还有点高级:Async-Wait best practices。
答案 1 :(得分:12)
resultTask
只是从GetBigList()
返回的列表,因此在那里不会发生异步。
您可以使用Task.Run
将任务卸载到线程池上的单独线程并返回等待的Task
对象:
// Bad code
public Task<List<MyObject>> GetBigListAsync()
{
return Task.Run(() => GetBigList());
}
虽然以上示例最符合您的尝试,但这不是最佳做法。尝试使GetBigList()
本身异步,或者如果真的没有办法,请将关于在单独的线程上执行代码的决定留给调用代码,并且不要在实现F.e中隐藏它。如果调用代码已经运行异步,则没有理由再生成另一个线程。 This article更详细地描述了这一点。
答案 2 :(得分:6)
几年后,但自.NET发生很大变化以来,人们搜索分辨率后,我觉得值得为该系列添加内容:
return await Task.FromResult(GetBigList())
答案 3 :(得分:-1)
它异步工作
// ...
bool result = await Task.Run(() => IAsyncTrue.GetBigList());
textBox1.Text = result.ToString(); //This line will execute before the code initiated by the previous line.
// ...
} // end class
public class IAsyncTrue
{
public static bool GetBigList()
{
// The first three lines are the code for checking asynchrony, you can delete them
Stopwatch sw = new Stopwatch();
sw.Start();
while (1 == 1) { if (sw.ElapsedMilliseconds > 2000) break; }
return true;
}
}