У меня есть 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). Ожидание в контексте пользовательского интерфейса сохраняет поток пользовательского интерфейса свободным, но ожидание при вызове веб-запроса будет ожидать завершения задачи, прежде чем отвечать на запрос, тем самым увеличивая время ответа без причины.
источник
MyAsyncMethod().Wait()
Ответы:
Если вы хотите получить исключение «асинхронно», вы можете сделать:
Это позволит вам иметь дело с исключением в потоке, отличном от «основного» потока. Это означает, что вам не нужно «ждать» вызова
MyAsyncMethod()
от потока, который вызываетMyAsyncMethod
; но все же позволяет вам делать что-то с исключением - но только если происходит исключение.Обновить:
технически, вы можете сделать что-то подобное с
await
:... что было бы полезно, если бы вам нужно было специально использовать
try
/catch
(илиusing
), но я считаю, чтоContinueWith
это немного более явно, потому что вы должны знать, чтоConfigureAwait(false)
значит.источник
Task
: public static class AsyncUtility {public static void PerformAsyncTaskWithoutAwait (эта задача Task, Action <Task> exceptionHandler) {var dummy = task.ContinueWith (t => exceptionHandler (t), TaskContinuationOptions.OnlyOnFapted); }} Использование: MyAsyncMethod (). PerformAsyncTaskWithoutAwait (t => log.ErrorFormat («Произошла ошибка при вызове MyAsyncMethod: \ n {0}», t.Exception));ConfiguratAwait(false)
не выполняется до тех пор, пока задача не завершится, но текущий поток не «ждет» (то есть блокирует) этого, следующая строка вызывается асинхронно для вызова await. БезConfigureAwait(false)
этой следующей строки будет выполняться в исходном контексте веб-запроса. СConfigurateAwait(false)
он выполняется в том же контексте, что и метод асинхронной (задача), освободив исходный контекст / нить продолжить ...Вы должны сначала рассмотреть вопрос о внесении
GetStringData
вasync
метод и онawait
задача вернулся изMyAsyncMethod
.Если вы абсолютно уверены, что вам не нужно обрабатывать исключения
MyAsyncMethod
или знать, когда они завершаются, то вы можете сделать это:Кстати, это не «общая проблема». Очень редко хочется выполнить какой-то код и не заботиться о том, завершается ли он, и не заботиться о том, успешно ли он завершается.
Обновить:
Поскольку вы работаете в ASP.NET и хотите вернуться раньше, мой блог на эту тему может оказаться полезным . Тем не менее, ASP.NET не был разработан для этого, и нет никаких гарантий что ваш код будет работать после возврата ответа. ASP.NET сделает все возможное, чтобы запустить его, но не может этого гарантировать.
Итак, это прекрасное решение для чего-то простого, например, для добавления события в журнал, где не имеет значения, потеряете ли вы кое-где. Это не очень хорошее решение для любых критически важных для бизнеса операций. В этих ситуациях необходимо принять более сложную архитектуру с постоянным способом сохранения операций (например, очереди Azure, MSMQ) и отдельным фоновым процессом (например, роль рабочего Azure, служба Win32) для их обработки.
источник
var _ = MyAsyncMethod();
на_ = MyAsyncMethod();
. Это по-прежнему позволяет избежать предупреждения CS4014, но делает его более явным, если вы не используете переменную.Ответом Питера Ричи было то, что я хотел, и статья Стивена Клири о раннем возвращении в ASP.NET была очень полезной.
Однако в качестве более общей проблемы (не специфичной для контекста ASP.NET) следующее консольное приложение демонстрирует использование и поведение ответа Питера с использованием
Task.ContinueWith(...)
GetStringData()
возвращается рано, не дожидаясь,MyAsyncMethod()
аMyAsyncMethod()
возникающие исключения рассматриваются в,OnMyAsyncMethodFailed(Task task)
а не вtry
/catch
околоGetStringData()
источник
Console.ReadLine();
и добавьте немного сна / задержки,MyAsyncMethod
и вы никогда не увидите исключения.Я в конечном итоге с этим решением:
источник
Это называется огнем и забудь, и для этого есть расширение .
Установите пакет nuget .
Использование:
источник
Я предполагаю, что возникает вопрос, зачем вам это нужно? Причина
async
в C # 5.0 заключается в том, что вы можете ждать результата. Этот метод на самом деле не асинхронный, а просто вызывается за раз, чтобы не слишком сильно мешать текущему потоку.Возможно, лучше начать поток и оставить его закончить самостоятельно.
источник
async
это немного больше, чем просто «ожидание» результата. «await» подразумевает, что строки, следующие за «await», выполняются асинхронно в том же потоке, который вызвал «await». Конечно, это можно сделать без «ожидания», но в итоге у вас будет куча делегатов и вы потеряете последовательный внешний вид кода (а также возможность использоватьusing
иtry/catch
...await
ключевое слово и не используетasync
ключевое слово, но нет никакого смысла в использованииasync
ключевого слова без его использованияawait
в определении этого метода.async
это немного больше, чем просто« ожидание »результата».async
Ключевые слова (вы подразумевал это ключевое слово, заключив его в обратных кавычках) означает ничего более , чем в ожидании результата. Это асинхронность, как и общие концепции CS, означает больше, чем просто ожидание результата.async
создает конечный автомат, который управляет любыми ожиданиями в асинхронном методе. Еслиawait
в методе нет s, он все равно создает этот конечный автомат, но метод не асинхронный. И еслиasync
метод возвращаетсяvoid
, ждать нечего. Таким образом, это больше, чем просто ожидание результата.async
ключевое слово. Все, что вам нужно сделать (и все, что действительно происходит в конечном итоге с конечным автоматом в этом особом случае), - это то, что метод запускается синхронно, а затем включается в завершенную задачу. Полагаю, технически вы не просто удаляете конечный автомат; вы удаляете конечный автомат и затем звонитеTask.FromResult
. Я предположил, что вы (а также авторы компиляторов) можете добавить приложение самостоятельно.В технологиях с циклами сообщений (не уверен, является ли ASP одним из них), вы можете заблокировать цикл и обрабатывать сообщения до завершения задачи и использовать ContinueWith, чтобы разблокировать код:
Этот подход аналогичен блокировке на ShowDialog и по-прежнему поддерживает отзывчивость пользовательского интерфейса.
источник
Я опаздываю на вечеринку, но я использую потрясающую библиотеку, на которую я не видел ссылок в других ответах
https://github.com/brminnick/AsyncAwaitBestPractices
Если вам нужно «выстрелить и забыть», вы вызываете метод расширения для задачи.
Передача действия onException в вызов гарантирует, что вы получите лучшее из обоих миров - нет необходимости ждать выполнения и замедлять работу пользователей, сохраняя при этом возможность обрабатывать исключение изящным образом.
В вашем примере вы бы использовали это так:
Это также дает ожидаемые AsyncCommands, реализующие ICommand из коробки, которая отлично подходит для моего решения MVVM Xamarin
источник
Решение - запустить HttpClient в другую задачу выполнения без контекста sincronization:
источник
Если вы действительно хотите это сделать. Просто для того, чтобы обратиться к «Вызов асинхронного метода в C # без ожидания», вы можете выполнить асинхронный метод внутри a
Task.Run
. Этот подход будет ждать доMyAsyncMethod
конца.await
асинхронно разворачиваетResult
вашу задачу, тогда как простое использование Result блокирует, пока задача не будет завершена.источник
Обычно асинхронный метод возвращает класс Task. Если вы используете
Wait()
метод илиResult
свойство и код генерирует исключение - в него включается тип исключенияAggregateException
- тогда вам нужно выполнить запрос,Exception.InnerException
чтобы найти правильное исключение.Но это также можно использовать
.GetAwaiter().GetResult()
вместо этого - оно также будет ожидать асинхронную задачу, но не будет переносить исключение.Итак, вот короткий пример:
Возможно, вы захотите также иметь возможность возвращать некоторый параметр из асинхронной функции - это может быть достигнуто путем предоставления дополнительного
Action<return type>
в асинхронную функцию, например, так:Обратите внимание, что асинхронные методы обычно имеют
ASync
суффиксное именование, чтобы избежать коллизий между функциями синхронизации с одинаковыми именами. (НапримерFileStream.ReadAsync
) - я обновил имена функций, чтобы следовать этой рекомендации.источник