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

У меня есть метод 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(), не ожидая этого, вызывает " Поскольку этот вызов не ожидается, текущий метод продолжает выполняться до завершения вызова" предупреждение в визуальной студии. На странице этого предупреждения указано:

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

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

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

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

Update:

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

Ответ 1

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

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

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

Update:

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

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

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

Ответ 2

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

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

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

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

Update:

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

Ответ 4

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

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);
}

Ответ 5

Это называется огнем и забудь, и для этого есть расширение.

Потребляет задачу и ничего с ней не делает. Полезно для вызова "забывай и забывай" асинхронных методов внутри асинхронных методов.

Установите пакет nuget.

Использование:

MyAsyncMethod().Forget();

Ответ 6

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

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

Ответ 7

В технологиях с циклами сообщений (не уверен, является ли ASP одним из них), вы можете заблокировать цикл и обрабатывать сообщения до завершения задачи и использовать ContinueWith, чтобы разблокировать код:

public void WaitForTask(Task task)
{
    DispatcherFrame frame = new DispatcherFrame();
    task.ContinueWith(t => frame.Continue = false));
    Dispatcher.PushFrame(frame);
}

Этот подход аналогичен блокировке на ShowDialog и по-прежнему поддерживает отзывчивость пользовательского интерфейса.