asynchronous/等待 – 什么时候返回一个任务与无效?
在什么情况下会想要使用
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)); }
1)通常,你会想要返回一个Task
。 主要的exception应该是当你需要有一个void
返回types(事件)。 如果没有理由不允许主叫方await
你的任务,为什么不允许呢?
2)返回void
async
方法在另一个方面是特殊的:它们表示顶级的asynchronous操作 ,并且当你的任务返回一个exception时有额外的规则。 最简单的方法是用一个例子来说明差异:
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(); }
f
的例外总是“被观察”。 留下顶级asynchronous方法的exception就像其他任何未处理的exception一样。 g
的例外从未被观察到。 当垃圾收集器清理任务时,它看到任务导致exception,没有人处理exception。 发生这种情况时, TaskScheduler.UnobservedTaskException
处理程序将运行。 你不应该让这种事情发生。 要使用你的例子,
public static async void AsyncMethod2(int num) { await Task.Factory.StartNew(() => Thread.Sleep(num)); }
是的,使用async
并await
这里await
,他们确保你的方法仍然正常工作,如果抛出exception。
有关更多信息,请参阅: http : //msdn.microsoft.com/en-us/magazine/jj991977.aspx
我遇到了这个有关async
所写的async
和void
非常有用的文章: http : //www.jaylee.org/post/2012/07/08/c-sharp-async-tips-and-tricks-part-2 -async-void.aspx
底线是一个async+void
可以使系统崩溃,通常只能在UI侧事件处理程序中使用。
其原因是由AsyncVoidMethodBuilder使用的同步上下文,在这个例子中没有。 当没有环境的同步上下文时,asynchronousvoid方法的主体未处理的任何exception在ThreadPool上重新运行。 虽然似乎没有其他合乎逻辑的地方可以抛出这种未处理的exception,但不幸的结果是进程正在终止,因为ThreadPool的未处理exception有效地终止了自.NET 2.0以来的进程。 您可以使用AppDomain.UnhandledException事件拦截所有未处理的exception,但是无法从此事件恢复进程。
在编写UI事件处理程序时,asynchronous无效方法在某种程度上是无痛的,因为exception处理方式与非asynchronous方法中的处理方式相同; 他们被扔在调度员。 有可能从这种例外中恢复过来,对于大多数情况来说,这是不正确的。 然而,在UI事件处理程序之外,asynchronous无效方法使用起来有些危险,可能并不容易find。
我从这个声明中得到了清晰的想法。
- asynchronous无效方法具有不同的error handling语义。 当exception被抛出asynchronous任务或asynchronous任务方法时,该exception被捕获并放置在任务对象上。 使用async void方法,不存在任何Task对象,因此asynchronousvoid方法中抛出的任何exception将直接在SynchronizationContext(SynchronizationContext表示可能执行的代码位置“where”代码)上引发,而asynchronousvoid方法开始
asynchronous无效方法的exception不能通过Catch抓住
private async void ThrowExceptionAsync() { throw new InvalidOperationException(); } public void AsyncVoidExceptions_CannotBeCaughtByCatch() { try { ThrowExceptionAsync(); } catch (Exception) { // The exception is never caught here! throw; } }
可以使用AppDomain.UnhandledException或GUI / ASP.NET应用程序的类似catch-all事件来观察这些exception,但将这些事件用于常规exception处理是不可维护的(它会使应用程序崩溃)。
-
asynchronous无效方法具有不同的组成语义。 asynchronous方法返回任务或任务可以很容易地使用await,Task.WhenAny,Task.WhenAll等。 返回void的asynchronous方法不提供一个简单的方法来通知他们已经完成的调用代码。 启动几个asynchronous无效方法很容易,但是确定何时完成并不容易。 Async void方法在启动和完成时会通知它们的SynchronizationContext,但是对于常规的应用程序代码,自定义的SynchronizationContext是一个复杂的解决scheme。
-
Async Void方法在使用同步事件处理程序时很有用,因为它们直接在SynchronizationContext上引发exception,这与同步事件处理程序的行为方式类似
有关更多详细信息,请查看此链接https://msdn.microsoft.com/zh-cn/magazine/jj991977.aspx
- C#HttpClient 4.5 multipart / form-data上传
- HttpClient.GetAsync与networking凭据
- 清洁的方式在C#中执行空检查?
- 在.NET 4.5中,我可以在C#5中做什么,而在.NET 4中,我无法在C#4中做这些?
- 在entity framework中设置数据库超时
- 等待运营商只能在一个asynchronous方法内使用
- 你必须把Task.Run放在一个方法来使其asynchronous?
- 使用Visual Studio 2012 RC的MVC 4 / Razor中的可移植类库
- 为什么会find一个types的初始化器抛出一个NullReferenceException?