С#, каков риск вызова асинхронного метода и никогда не ожидание возвращенной задачи или сохранение ссылок на указанную задачу

Я знаю, что обработка исключений может стать странной, если вы никогда не ждете возвращаемого Task, но если вас на самом деле не волнуют результаты и/или успех асинхронного метода, имеет ли значение, если вы не храните ссылку на задача в любом месте? По сути, я просто хочу выстрелить и забыть метод, и я хочу знать, насколько педантичным я должен быть при этом.

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

public async Task Dispose(){
    try{
        ...
    }catch{} //might add some minimal logging, but probably wont
}

В порядке убывания лени реализации, которые я рассматривал,

public void DisposeFoo(){
   foo.Dispose()//feed the task to the void
}

является ли вышеуказанное более или менее безопасным, чем

private Task DisposeFooTask;
public void DisposeFoo(){
   DisposeFooTask= foo.Dispose()//store the task and never touch it again
}

И я также нашел этот подход на SO

static async void FireAndForget(this Task task)
{
   try
   {
        await task;
   }
   catch (Exception e)
   {
       // log errors
   }
}
public void DisposeFoo(){
   foo.Dispose().FireAndForget();
}

Есть ли риск ошибки в foo.Dispose(), избегающей любых перехватов попыток и убивающей мою систему, если я проигнорирую задачу? И если нет, есть ли риск того, что что-то вроде потока, выполняющего foo.Dispose(), откажется от жизни из-за того, что задача больше не находится в области видимости? Или опасность моего ленивого кодирования заключается исключительно в сокрытии исключений?

Если вы используете IHttpClientFactory, в удалении нет необходимости, новая реализация очищает все ресурсы. Во-вторых, не имеет значения, если вы не ждете, вам просто нужно помнить об ошибках

TheGeneral 14.12.2020 06:31

Исключением из этого правила является то, что вы читаете только заголовки ответа с помощью HttpCompletionOption.ResponseHeadersRead, и в этом случае ответ не буферизуется и его необходимо удалить.

TheGeneral 14.12.2020 06:42

Что касается IHttpClientFactory, если все это находится в одной группе методов, просто используйте использование там, где вы обычно это делаете (без вреда), ловите и регистрируйте любые ошибки и отбрасывайте. Или, если вам нравится создавать асинхронный метод void FireAndForget, который ловит и отбрасывает, кроме этого, на самом деле больше не о чем говорить.

TheGeneral 14.12.2020 06:44

Если вам все равно, бросит ли foo.Dispose() или нет, то почему вас волнует, утилизируется foo или нет? Просто не утилизируйте его вообще. Что самое худшее, что может случиться?

Theodor Zoulias 14.12.2020 08:23

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

The Lemon 14.12.2020 10:26

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

The Lemon 14.12.2020 10:27
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
611
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Есть ли риск ошибки в foo.Dispose(), избегающей любых перехватов попыток и убивающей мою систему, если я проигнорирую задачу?

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

И если нет, есть ли риск того, что что-то вроде потока, выполняющего foo.Dispose(), откажется от жизни из-за того, что задача больше не находится в области видимости?

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

Или опасность моего ленивого кодирования заключается исключительно в сокрытии исключений?

Да, насколько я могу судить, худшим эффектом было бы сокрытие потенциальных исключений.

Ответ принят как подходящий

если вы на самом деле не заботитесь о результатах и/или успехе асинхронного метода, имеет ли значение, если вы нигде не храните ссылку на задачу?

Задача, как правило, не подлежит сборке мусора, пока не завершится; это потому, что есть какой-то обратный вызов (который завершит задачу), который ссылается на эту задачу, и эти обратные вызовы обычно являются корневыми (в терминах GC).

Когда задача игнорируется (то есть выполняется, но не наблюдается), она может стать пригодной для сборки мусора. Если эта задача завершится с исключением, то она поднимет TaskScheduler.UnobservedTaskException при сборе мусора. Это событие раньше приводило к сбою процесса, но больше не приводит к сбою.

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

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

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

Вызов dispose как задачи «выстрелил и забыл» был бы в порядке. Завершение работы в этом случае не рассматривается, так как ОС все равно очистится.

Однако вообще вызывать dispose в задаче довольно странно. Удаление обычно происходит очень быстро (например, установка одного или двух полей в буквальном смысле), поэтому нет смысла переносить эту работу в фоновый поток.

Это потому, что я жду завершения любых невыполненных вызовов, прежде чем удалять фактический httpClient и отменять tokenSource, но это также то, что мне уже давно интересно

The Lemon 15.12.2020 13:45

Если вы также запускаете и забываете сами эти вызовы API, то вам следует знать, что они могут быть отменены при выходе из вашего приложения. Таким образом, заставляя их запустить и забыть, вы заявляете, что вам все равно, завершатся ли они. Что мне кажется гораздо опаснее.

Stephen Cleary 15.12.2020 14:11

Другие вопросы по теме

Почему моя маленькая программа продолжает использовать все больше и больше оперативной памяти и большую часть процессора?
Django/Ajax: как асинхронно фильтровать набор запросов поля формы?
Время выполнения измерения узла — возвращаемое значение из асинхронного режима, переданного в качестве параметра другой функции
Асинхронный JavaScript и ввод/вывод
Угловой асинхронный канал не работает для обновления источника изображения
Самый эффективный способ сохранить файл на диске при выполнении асинхронной работы в веб-запросе ASP.Net CORE
Javascript и асинхронная проблема (построение матрицы расстояний с помощью yandex maps api)
Javascript/Vue Выполнение функции за другой (синхронно)
Как использовать async/await, чтобы получить ввод от пользователя, но подождать, пока весь оператор условия не будет прочитан перед разрешением?
Promise.All условно ждут обещания