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 /await函数比较

它们是不一样的,当你添加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();
}

第一个函数有点浪费。asyncawait都没有给你任何好处。我为什么这么说?好吧,让我们快速回顾一下await通常的好处。

await允许您做的是在等待的任务完成后恢复执行方法的剩余部分。在您的情况下,没有"方法的剩余部分",因为return await是方法的最后一条语句。

为什么这是浪费?好吧,通过标记你的方法async,你基本上是告诉编译器生成所有的机制(即状态机),以允许你在每次等待后在同一方法内恢复执行。

这种机制在您的情况下是无用的,因为等待之后没有任何东西可以恢复执行,所以您最好使用而不是将方法标记为async,而不是return await,只是简单地返回FirstOrDefaultAsync生成的任务。

这样做仍然会使函数返回并表现为异步。请记住,asyncawait实际上并不是使函数异步执行的原因。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,编译器将生成状态机。

第二种方法:您正在返回"热任务"-已经完成的任务。此方法将像普通方法一样工作。

顺便说一句,在第二个场景中缓存这些任务是一个好主意。例如,您可以创建字典并返回缓存任务。如果你这样做,你不会每次都在堆上分配新的任务。