Async /await函数比较
本文关键字:比较 函数 await Async | 更新日期: 2023-09-27 18:10:31
我试图理解async/await,我想知道这两种方法是否工作相同。如果不是,你能解释为什么吗?
public async Task<Client> GetClient()
{
return await _clientRepository.GetAll().Where(x => x.Id == 1).FirstOrDefaultAsync();
}
public Task<Client> GetClient2()
{
return Task.FromResult(_clientRepository.GetAll().Where(x => x.Id == 1).FirstOrDefault());
}
public async Task Run()
{
var result = await GetClient();
var result2 = await GetClient2();
}
它们是不一样的,当你添加async关键字时,你启用了以下两个功能:
-
标记的async方法可以使用Await或Await来指定挂起点。await操作符告诉编译器,在等待的异步进程完成之前,异步方法不能继续执行。同时,控制返回给async方法的调用者。
async方法在await表达式处的挂起并不构成该方法的退出,并且最终块不会运行。
-
标记的async方法本身可以被调用它的方法等待。
你应该在这里阅读async/await文档:https://msdn.microsoft.com/en-us/library/hh191443.aspx
让我指出一些关于你的函数的事情:
public async Task<Client> GetClient()
{
return await _clientRepository.GetAll().Where(x => x.Id == 1).FirstOrDefaultAsync();
}
第一个函数有点浪费。async
和await
都没有给你任何好处。我为什么这么说?好吧,让我们快速回顾一下await
通常的好处。
await
允许您做的是在等待的任务完成后恢复执行方法的剩余部分。在您的情况下,没有"方法的剩余部分",因为return await
是方法的最后一条语句。
为什么这是浪费?好吧,通过标记你的方法async
,你基本上是告诉编译器生成所有的机制(即状态机),以允许你在每次等待后在同一方法内恢复执行。
这种机制在您的情况下是无用的,因为等待之后没有任何东西可以恢复执行,所以您最好使用而不是将方法标记为async
,而不是return await
,只是简单地返回FirstOrDefaultAsync
生成的任务。
这样做仍然会使函数返回并表现为异步。请记住,async
和await
实际上并不是使函数异步执行的原因。async/await
只是帮助设置机制,为方法中的各个等待点提供"书签",以便在每个等待任务完成后可以在那里恢复执行。
现在我们来讨论第二个函数:
public Task<Client> GetClient2()
{
return Task.FromResult(_clientRepository.GetAll().Where(x => x.Id == 1).FirstOrDefault());
}
这个函数根本不是异步的。它将完全同步执行,根本不产生线程。
即使你这样做了:
public async Task<Client> GetClient2()
{
return await Task.FromResult(_clientRepository.GetAll().Where(x => x.Id == 1).FirstOrDefault());
}
函数仍然是完全同步的。请记住,async/await
都是关于设置机制和书签的,但实际上对代码是同步执行还是异步执行没有任何作用。
为什么会阻塞呢?因为FirstOrDefault()
不返回任务,所以这意味着它必须返回Client
对象。这意味着它不能返回任何东西,直到它完全完成linq
链的执行。然后,您的Task.FromResult
只是获取此值并将其包装在预完成的任务中。
再回顾一下:
只有当你需要在你的方法中间恢复执行时才使用async/await
。
的例子:
public async Task<boolean> IsIntegerIGetFromRemoteServerPostitiveAsync(){
int result = await GetSomeIntegerAsync();
Console.WriteLine('Resuming execution of the method');
return i>0;
}
如果你发现你有一个单一的等待,它是方法的最后一行,那么不要使用async/await
,只是返回任务而不是等待它。这避免了不必要的开销。
的例子:
public Task<string> GetUserInformationAsync(string username){
var url = $"http://userinfo.com?username={username}"
return GetSomeJsonFromHttpServerAsync(url); //Assuming this returns Task<string>
}
第一个方法:Async关键字给出生成状态机的编译器信号。事件,如果将void方法标记为async,编译器将生成状态机。
第二种方法:您正在返回"热任务"-已经完成的任务。此方法将像普通方法一样工作。
顺便说一句,在第二个场景中缓存这些任务是一个好主意。例如,您可以创建字典并返回缓存任务。如果你这样做,你不会每次都在堆上分配新的任务。