async/await-何时返回Task vs void



在什么情况下需要使用

public async Task AsyncMethod(int num)

而不是

public async void AsyncMethod(int num)

我能想到的唯一场景是,如果你需要任务能够跟踪其进度。

此外,在下面的方法中,async和wait关键字是否没有必要?

public static async void AsyncMethod2(int num)
{
    await Task.Factory.StartNew(() => Thread.Sleep(num));
}
  1. 通常,您希望返回一个Task。主要的例外情况应该是需要具有void返回类型(用于事件)。如果没有理由不允许调用方await执行您的任务,为什么不允许呢?

  2. 返回voidasync方法在另一个方面是特殊的:它们表示顶级异步操作,并且在任务返回异常时具有其他规则。最简单的方法是通过一个例子来显示差异:

static async void f()
{
    await h();
}
static async Task g()
{
    await h();
}
static async Task h()
{
    throw new NotImplementedException();
}
private void button1_Click(object sender, EventArgs e)
{
    f();
}
private void button2_Click(object sender, EventArgs e)
{
    g();
}
private void button3_Click(object sender, EventArgs e)
{
    GC.Collect();
}

CCD_ 6的异常总是";观察到";。离开顶级异步方法的异常会像对待其他未处理的异常一样简单处理。g的异常从未被观察到。当垃圾收集器来清理任务时,它会发现该任务导致了异常,而没有人处理该异常。当这种情况发生时,TaskScheduler.UnobservedTaskException处理程序将运行。你永远不应该让这种事情发生。举个例子,

public static async void AsyncMethod2(int num)
{
    await Task.Factory.StartNew(() => Thread.Sleep(num));
}

是的,在这里使用asyncawait,它们可以确保在抛出异常时您的方法仍然正常工作。

有关更多信息,请参阅:https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming

我看到了Jérôme Laban写的这篇关于asyncvoid的非常有用的文章:https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html

最重要的是,async+void可能会使系统崩溃,通常只应用于UI端的事件处理程序。

这背后的原因是AsyncVoidMethodBuilder,在本例中为none。当没有ambient Synchronization Context,未由处理的任何异常异步void方法的主体在ThreadPool上重新抛出。虽然似乎没有其他合乎逻辑的地方可以处理这种问题可能会引发异常,不幸的后果是正在终止,因为ThreadPool上未处理的异常有效地终止了自.NET 2.0以来的进程。你可以拦截使用AppDomain.UnhandledException事件的所有未处理的异常,但是没有办法从这个事件中恢复进程。

在编写UI事件处理程序时,异步void方法在某种程度上是无痛,因为异常处理方式与非异步方法;它们被扔到Dispatcher上。有一个从此类异常中恢复的可能性,非常正确在大多数情况下。然而,在UI事件处理程序之外,async void方法在某种程度上使用起来很危险,而且可能不那么容易找到。

调用异步void的问题是

你甚至连任务都拿不回来。你无法知道函数的任务何时完成。----异步和等待中的速成课程|旧的新事物

以下是调用异步函数的三种方法:

async Task<T> SomethingAsync() { ... return t; }
async Task SomethingAsync() { ... }
async void SomethingAsync() { ... }

在所有情况下,函数都被转换为一系列任务。不同之处在于函数返回的内容。

在第一种情况下,函数返回一个最终生成t.的任务

在第二种情况下,函数返回一个没有产品的任务,但您可以仍在等待它,以了解它何时运行完成。

第三种情况是令人讨厌的。第三种情况与第二种情况类似,只是你甚至连任务都拿不回来。你不知道什么时候函数的任务已完成。

异步无效的情况是"空"的情况;火灾和忘记":你启动了任务链,但你不在乎它何时完成完成。当函数返回时,您只知道直到执行了第一个等待。一切在第一次等待之后将在将来某个未指定的点运行,而您没有访问.

我认为您也可以使用async void启动后台操作,只要您小心捕捉异常即可。想法?

class Program {
    static bool isFinished = false;
    static void Main(string[] args) {
        // Kick off the background operation and don't care about when it completes
        BackgroundWork();
        Console.WriteLine("Press enter when you're ready to stop the background operation.");
        Console.ReadLine();
        isFinished = true;
    }
    // Using async void to kickoff a background operation that nobody wants to be notified about when it completes.
    static async void BackgroundWork() {
        // It's important to catch exceptions so we don't crash the appliation.
        try {
            // This operation will end after ten interations or when the app closes. Whichever happens first.
            for (var count = 1; count <= 10 && !isFinished; count++) {
                await Task.Delay(1000);
                Console.WriteLine($"{count} seconds of work elapsed.");
            }
            Console.WriteLine("Background operation came to an end.");
        } catch (Exception x) {
            Console.WriteLine("Caught exception:");
            Console.WriteLine(x.ToString());
        }
    }
}

简要说明:
async Task<T> method()wait可用于等待,直到执行完成,它将是T
类型的return valueasync Task method()wait可用于等待,直到执行完成,但未返回任何数据
async void method()不能等待并且没有返回任何数据[示例:异步事件执行]

我的答案很简单你不能等待无效方法

Error   CS4008  Cannot await 'void' TestAsync   e:testTestAsyncTestAsyncProgram.cs

因此,如果方法是async,最好是awalite,因为你可能会失去async的优势。

最新更新