如何在不等待的情况下安全地调用C#中的asynchronous方法

我有一个不返回数据的async方法:

 public async Task MyAsyncMethod() { // do some stuff async, don't return any data } 

我从另一个返回一些数据的方法调用这个:

 public string GetStringData() { MyAsyncMethod(); // this generates a warning and swallows exceptions return "hello world"; } 

在不等待它的情况下调用MyAsyncMethod()会导致在Visual Studio中出现“ 因为此调用未被等待,当前方法在调用完成之前继续运行 ”警告。 在该警告的页面上,它指出:

只有在确定不希望等待asynchronous调用完成并且调用的方法不会引发任何exception时 ,才应该考虑抑制警告。

我确定我不想等待电话完成; 我不需要或有时间。 但是这个调用可能会引发exception。

我已经偶然发现了这个问题几次,我确定这是一个常见的问题,必须有一个共同的解决scheme。

如何在不等待结果的情况下安全地调用asynchronous方法?

更新:

对于提示我只是等待结果的人,这是响应我们的Web服务(ASP.NET Web API)上的Web请求的代码。 等待在UI上下文中保持UI线程空闲,但等待Web请求调用等待Task完成,然后再响应请求,从而无需理由地增加响应时间。

如果你想“asynchronous”得到exception,你可以这样做:

  MyAsyncMethod(). ContinueWith(t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted); 

这将允许您处理除“主”线程以外的线程上的exception。 这意味着您不必从调用MyAsyncMethod的线程“等待”对MyAsyncMethod()的调用; 但是,仍然允许你做一些例外 – 但只有在发生exception的时候。

更新:

从技术上讲,你可以做类似的await

 try { await MyAsyncMethod().ConfigureAwait(false); } catch (Exception ex) { Trace.WriteLine(ex); } 

…如果你需要专门使用try / catch (或using ),这将是有用的,但我觉得ContinueWith更清晰一些,因为你必须知道什么是ConfigureAwait(false)

您应该首先考虑将GetStringDataasync方法,并awaitMyAsyncMethod返回的任务。

如果你确定你不需要处理来自MyAsyncMethodexception或者知道何时完成,那么你可以这样做:

 public string GetStringData() { var _ = MyAsyncMethod(); return "hello world"; } 

顺便说一下,这不是一个“常见问题”。 想要执行某些代码是非常罕见的,不关心它是否完成不关心它是否成功完成。

更新:

由于您使用的是ASP.NET并希望尽早返回,因此您可能会发现关于此主题的博文 。 但是,ASP.NET并不是为此devise的,因此不能保证在返回响应后您的代码将运行。 ASP.NET将尽其所能让它运行,但不能保证它。

所以,对于简单的事情来说,这是一个很好的解决scheme,就像把一个事件扔进一个日志一样,如果你在这里和那里都失去了一点,这并不重要。 对于任何一种关键业务操作来说,这都不是一个好的解决scheme。 在这些情况下,您必须采用更复杂的体系结构,以持久的方式保存操作(例如,Azure队列,MSMQ)和单独的后台进程(例如Azure Worker Role,Win32 Service)来处理它们。

Peter Ritchie的回答是我想要的,而Stephen Cleary关于在ASP.NET中返回的文章非常有帮助。

然而,作为一个更一般的问题(不是特定于ASP.NET上下文),以下控制台应用程序演示了使用Task.ContinueWith(...)的Peter答案的用法和行为。

 static void Main(string[] args) { try { // output "hello world" as method returns early Console.WriteLine(GetStringData()); } catch { // Exception is NOT caught here } Console.ReadLine(); } public static string GetStringData() { MyAsyncMethod().ContinueWith(OnMyAsyncMethodFailed, TaskContinuationOptions.OnlyOnFaulted); return "hello world"; } public static async Task MyAsyncMethod() { await Task.Run(() => { throw new Exception("thrown on background thread"); }); } public static void OnMyAsyncMethodFailed(Task task) { Exception ex = task.Exception; // Deal with exceptions here however you want } 

GetStringData()在不等待MyAsyncMethod()情况下返回,并且在OnMyAsyncMethodFailed(Task task)中处理MyAsyncMethod()中引发的exception,而不是GetStringData()

我结束这个解决scheme:

 public async Task MyAsyncMethod() { // do some stuff async, don't return any data } public string GetStringData() { // Run async, no warning, exception are catched RunAsync(MyAsyncMethod()); return "hello world"; } private void RunAsync(Task task) { task.ContinueWith(t => { ILog log = ServiceLocator.Current.GetInstance<ILog>(); log.Error("Unexpected Error", t.Exception); }, TaskContinuationOptions.OnlyOnFaulted); } 

我想问题出现了,你为什么需要这样做呢? 在C#5.0中async的原因是你可以等待一个结果。 这个方法实际上并不是asynchronous的,而是一次只调用一次,以免对当前线程造成太大干扰。

也许最好是开始一个线程,并让它自行完成。