提问者:小点点

我们应该如何使用异步等待?[副本]


我正在研究如何使用async await,但是当我们有多个方法相互调用时,我就不太明白了。我们应该总是使用await,还是应该只在实际准备使用结果时才使用await?

例如,我们是否应该这样做:

async Task<string[]> FooAsync()
{
    var info = await Func1();
    return info.split('.');
}

async Task<string> Func1()
{
    return await Func2();
}

async Task<string> Func2()
{
    return await tcpClient.ReadStringAsync();
}

或者像这样:

async Task<string[]> FooAsync()
{
    var info = await Func1();
    return info.split('.');
}

Task<string> Func1()
{
    return Func2();
}

Task<string> Func2()
{
    return tcpClient.ReadStringAsync();
}

例1:我们是否应该在每个方法中都使用await?
orbr>根据示例2,当我们开始使用结果时,是否应该只在最顶层的方法上使用await?


共3个答案

匿名用户

每次调用时,它都会创建一组代码来捆绑变量,捕获同步上下文(如果适用)并在中创建一个延续。

本质上,返回一个不带关键字的将给您带来很小的运行时效率,并节省大量CIL。请注意,。NET中的异步特性已经进行了许多优化。还要注意(重要的是),在语句中返回可能会引发一个已经释放的异常。

你可以在这里比较一下铅笔和管道的区别

因此,如果您的方法只是转发一个而不想从中得到任何东西,那么您可以很容易地删除关键字并直接返回

更重要的是,有时我们做的不仅仅是转发,还涉及到分支。这就是发挥作用的地方,它们可以帮助处理方法中可能出现的逻辑。即,如果您想给出一个结果(there和then),或者返回一个完成的(分别)。

最后,Async和Await模式在处理异常时有细微的区别。如果要返回,则可以使用在返回的上弹出任何异常,就像方法通常所做的那样。

荒谬的例子

public Task<int> DoSomethingAsync(int someValue)
{
   try
   {
      if (someValue == 1)
         return Task.FromResult(3); // Return a completed task

      return MyAsyncMethod(); // Return a task
   }
   catch (Exception e)
   {
      return Task.FromException<int>(e); // Place exception on the task
   }
}

null

大约在这个时候,我会查找stack overflow用户和作者Stephen Cleary和Parallel先生Stephen toub。他们有大量的博客和书籍专门讨论异步和等待模式,所有的陷阱,编码礼仪和更多的信息,您一定会发现这些信息很有趣。

匿名用户

这两个选项都是合法的,而且每个选项都有自己的场景,在那里它比另一个更有效。

当然,当您想要处理异步方法的结果或处理当前方法中可能的异常时,请始终使用await

public async Task Execute()
{
    try
    {
        await RunAsync();
    }
    catch (Exception ex)
    {
        // Handle thrown exception
    }
}

如果在当前方法中没有使用异步方法的结果-返回任务。这种方法会将状态机的创建延迟到调用方或等待最终任务的地方。正如评论中所指出的那样,可以使执行更有效一点。

但在某些情况下,您必须等待任务,甚至您对结果什么也不做,也不想处理可能的异常

public Task<Entity> GetEntity(int id)
{
    using (var context = _contextFactory.Create())
    {
        return context.Entities.FindAsync(id);
    }
}

在上述方案中,可以返回未完成的任务,此任务将直接返回给调用方,并释放在语句中创建的对象。br>稍后当调用方“等待”任务时将引发异常,因为它将尝试使用已释放的对象(CodeContext/Code)。

public async Task<Entity> GetEntity(int id)
{
    using (var context = _contextFactory.Create())
    {
        return await context.Entities.FindAsync(id);
    }
}

传统上,关于Async Await的回答必须包括Stephen Cleary's blogbr>ElidingAsync And Await的链接

匿名用户

Await是一个排序特性,它允许调用者接收异步方法的结果,并对其执行某些操作。如果不需要处理异步函数的结果,则不必等待它。

在您的示例中,不处理调用的异步函数的返回值,因此不必等待它们。

相关问题