Как безопасно вызывать метод async на C # без ожидания

У меня есть метод 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. На странице этого предупреждения указано:

Вам следует рассмотреть возможность подавления предупреждения только в том случае, если вы уверены, что не хотите ждать завершения асинхронного вызова и что вызываемый метод не будет создавать никаких исключений .

Я уверен, что не хочу дождаться завершения звонка; Мне не нужно или есть время. Но вызов может вызвать исключения.

Я несколько раз наткнулся на эту проблему, и я уверен, что это общая проблема, которая должна иметь общее решение.

Как безопасно вызывать метод асинхронизации, не ожидая результата?

Обновить:

Для людей, предлагающих, что я просто жду результата, это код, который отвечает на веб-запрос в нашем веб-сервисе (ASP.NET Web API). В ожидании контекста пользовательского интерфейса поддерживает stream пользовательского интерфейса, но ожидание вызова веб-запроса будет ждать завершения задачи перед ответом на запрос, тем самым увеличивая время ответа без причины.

Если вы хотите получить исключение «асинхронно», вы можете сделать следующее:

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

Это позволит вам справиться с исключением из streamа, отличного от «основного» streamа. Это означает, что вам не нужно «ждать» вызова MyAsyncMethod() из streamа, который вызывает MyAsyncMethod ; но все же позволяет вам делать что-то с исключением – но только в случае возникновения исключения.

Обновить:

технически вы можете сделать что-то подобное с await :

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

… что было бы полезно, если бы вам нужно было специально использовать try / catch (или using ), но я считаю, что ContinueWith будет немного более явным, потому что вы должны знать, что означает ConfigureAwait(false) .

Вы должны сначала подумать о том, чтобы GetStringData использовать метод async и MyAsyncMethod задачу, возвращенную из MyAsyncMethod .

Если вы абсолютно уверены, что вам не нужно обрабатывать исключения из MyAsyncMethod или знать, когда они завершатся, вы можете сделать это:

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

Кстати, это не «общая проблема». Очень редко нужно выполнять какой-то код и не заботиться о том, завершает ли он и не заботится, успешно ли он завершается.

Обновить:

Поскольку вы на ASP.NET и хотите вернуться раньше, вы можете найти мое сообщение в блоге по теме полезной . Однако ASP.NET не был разработан для этого, и нет гарантии, что ваш код будет запущен после ответа ответа. ASP.NET сделает все возможное, чтобы запустить его, но он не может этого гарантировать.

Таким образом, это прекрасное решение для чего-то простого, например, для передачи события в журнал, где это не имеет большого значения, если вы потеряете несколько здесь и там. Это нехорошее решение для любых бизнес-критических операций. В этих ситуациях вы должны использовать более сложную архитектуру с постоянным способом сохранения операций (например, Azure Queues, MSMQ) и отдельный фоновый процесс (например, роль рабочего места Azure, служба Win32) для их обработки.

Ответ Peter Ritchie был тем, что я хотел, и статья Стивена Клири о возвращении на раннем этапе ASP.NET была очень полезна.

Однако, как более общая проблема (не специфичная для контекста ASP.NET), следующее консольное приложение демонстрирует использование и поведение ответа Питера с помощью Task.ContinueWith(...)

 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() и исключения, которые были MyAsyncMethod() в MyAsyncMethod() , рассматриваются в OnMyAsyncMethodFailed(Task task) а не в try / catch вокруг GetStringData()

Я получаю это решение:

 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(); log.Error("Unexpected Error", t.Exception); }, TaskContinuationOptions.OnlyOnFaulted); } 

Думаю, возникает вопрос: зачем вам это нужно? Причина async в C # 5.0 заключается в том, что вы можете ждать результата. Этот метод на самом деле не asynchronous, а просто вызываемый одновременно, чтобы не мешать слишком большому streamу текущего streamа.

Возможно, лучше начать нить и оставить ее закончить самостоятельно.

  • Как регистрировать все брошенные исключения?
  • Обработка InterruptedException в Java
  • Как создать фоновый рабочий stream, установленный в Single Thread Apartment?
  • Давайте будем гением компьютера.