在异步函数中为什么需要使用await?

3

假设我有这样一个方法:

private async Task SomeMethod()
{
  await DoSomethingAsync();
  await DoSomethingElseAsync();
  return;
}

既然DoSomethingElseAsync返回一个Task,似乎你应该能够这样做:

private async Task SomeMethod()
{
  await DoSomethingAsync();
  return DoSomethingElseAsync();
}

但编译器会抱怨:

由于'SomeMethod'是一个返回'Task'的异步方法,因此返回关键字后面不能跟着一个对象表达式。你是否打算返回'Task<T>'?

为什么会这样呢?


4
@YvetteColomb,这并不是和此问题完全相同的问题。楼主不是在询问何时使用await。而是在问“为什么我不能返回Task?” - Panagiotis Kanavos
@YvetteColomb 这不是重复问题,您所引用的那个问题是关于何时使用await,而这个问题是在询问为什么第二种方法不能简单地返回而不写await,我认为英语非常清楚地将两者区分开来。 - Akash Kava
4
在第一个 await DoSomethingAsync(); 完成之前,该方法已经返回给调用方(因为它是一个异步方法)。因此,在该 await 之后无法返回特定的值 - 调用方已经在此时收到了返回值并继续执行。 - Evk
3个回答

5

这类似于yield returnreturn的工作原理。对于迭代器,您可以使用其中之一。

public IEnumerable<int> SomeIterator()
{
    for(int I = 0; I < 10; I++) yield return I;
}

public IEnumerable<int> SomeIterator()
{
    return Enumerable.Range(0, 10); // return result of another iterator.
}

但你不能两者兼得。这是不可行的,因为迭代器要么被编译器转换为一个类以处理使用 yield 进行延迟迭代,要么就像其他正常方法一样返回其他内容。

public IEnumerable<int> SomeIterator() // not valid
{
    for(int I = 0; I < 10; I++) yield return I;
    return Enumerable.Range(0, 10); 
}

故事同样适用于返回和async/await。对于具有Task类型的返回类型的方法,你可以返回Task或者使用async/await。
对于Task<T>,如果你使用await,则必须返回T,但你不能返回Task<T>,因为该方法被编译成状态机,所以方法必须返回T。(对于Task方法是void)
如果你不使用async/await,那么该方法将与其他普通方法完全相同。

这样做,再加上Evk的评论,看起来非常有道理。不过我仍然觉得有点失望,因为 await Thing1(); await Thing2(); returnawait Thing1(); return Thing2(); 在底层代码中并没有简单地编译成相同的代码,尽管在逻辑上仍然是有意义的(至少我觉得是!) - DJL

0
当你使用await时,控制流可能会离开当前方法并返回给调用者。假设DoSomethingAsync是一些长时间运行的操作。你调用了SomeMethodDoSomethingAsync任务已经开始,但然后你不能在该方法中等待它完成,否则什么都不会是"异步"的。因此,控制流离开Method并应向调用者提供返回值。返回值是一个任务,当整个SomeMethod完成时才会完成。它可以带有或不带结果(TaskTask<T>返回值)。因此,在await之后返回的内容不能是SomeMethod的返回类型,它只能是结果类型T(如果SomeMethod返回任务)或简单的return以指示SomeMethod完成(如果它返回简单的Task)。

0
在普通方法中,return的意思是“从方法中返回此值(如果有)”。在async方法中,return的含义变为“将返回的Task的结果设置为此值(如果有)”。
但是你不能将两者结合起来:在async Task方法中,你不能直接return一个Task。其中一个原因是,如果你使用了await,那么方法实际上已经返回了一个Task,它不能再返回另一个。
在返回方面,async Task方法的行为类似于void方法,只允许return;,而不允许return value;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接