在什么情况下会使用
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));
}
我偶然发现了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.
调用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.