在什么情况下会使用

public async Task AsyncMethod(int num)

而不是

public async void AsyncMethod(int num)

我能想到的唯一情况是,如果您需要任务能够跟踪其进度。

此外,在下面的方法中,async和await关键字是不必要的吗?

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

当前回答

我认为你也可以使用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() await可用于等待执行完成,它将返回类型为T的值 async Task方法await可用于等待执行完成但不返回数据 async void方法()不能等待,没有数据返回[示例:async事件执行]

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

Error   CS4008  Cannot await 'void' TestAsync   e:\test\TestAsync\TestAsyncProgram.cs

所以如果方法是异步的,最好是可等待的,因为你会失去异步的优势。

调用async void的问题是

你连任务都拿不回来。您无法知道函数的任务何时完成。——速成班在async和等待|旧的新事物

下面是调用async函数的三种方法:

async Task<T> SomethingAsync() { ... return t; } async Task SomethingAsync() { ... } async void SomethingAsync() { ... } In all the cases, the function is transformed into a chain of tasks. The difference is what the function returns. In the first case, the function returns a task that eventually produces the t. In the second case, the function returns a task which has no product, but you can still await on it to know when it has run to completion. The third case is the nasty one. The third case is like the second case, except that you don't even get the task back. You have no way of knowing when the function's task has completed. The async void case is a "fire and forget": You start the task chain, but you don't care about when it's finished. When the function returns, all you know is that everything up to the first await has executed. Everything after the first await will run at some unspecified point in the future that you have no access to.

我认为你也可以使用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());
        }
    }
}

我偶然发现了Jérôme Laban写的关于async和void的非常有用的文章: https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html

底线是async+void会使系统崩溃,通常只应该在UI侧事件处理程序上使用。

The reason behind this is the Synchronization Context used by the AsyncVoidMethodBuilder, being none in this example. When there is no ambient Synchronization Context, any exception that is unhandled by the body of an async void method is rethrown on the ThreadPool. While there is seemingly no other logical place where that kind of unhandled exception could be thrown, the unfortunate effect is that the process is being terminated, because unhandled exceptions on the ThreadPool effectively terminate the process since .NET 2.0. You may intercept all unhandled exception using the AppDomain.UnhandledException event, but there is no way to recover the process from this event. When writing UI event handlers, async void methods are somehow painless because exceptions are treated the same way found in non-async methods; they are thrown on the Dispatcher. There is a possibility to recover from such exceptions, with is more than correct for most cases. Outside of UI event handlers however, async void methods are somehow dangerous to use and may not that easy to find.