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

10

Я только что узнал, что .NET 4.5 представил изменение в том, как Taskобрабатываются исключения внутри . А именно они тихо подавлены.

Официальное обоснование того, почему это было сделано, выглядит так: «Мы хотели быть более дружелюбными к неопытным разработчикам»:

В .NET 4.5 задачи имеют значительно большее значение, чем в .NET 4, поскольку они встроены в языки C # и Visual Basic как часть новых асинхронных функций, поддерживаемых этими языками. По сути, это выводит Задачи из сферы опытных разработчиков в сферу деятельности каждого. В результате это также приводит к новому набору компромиссов в отношении того, насколько строгой должна быть обработка исключений.

( источник )

Я научился верить, что многие решения в .NET были приняты людьми, которые действительно знают, что они делают, и, как правило, есть веская причина, по которой они решают. Но этот ускользает от меня.

Если бы я проектировал свою собственную библиотеку асинхронных задач, в чем преимущество проглатывания исключений, которые разработчики Framework увидели, которых я не вижу?

Роман Старков
источник
4
+1. Хороший вопрос, учитывая тот факт, что нераспространение исключений, которые вы не можете обработать, является плохой практикой, даже если не учитывать асинхронный контекст. Кроме того, спор о неопытных разработчиках довольно слаб, ИМХО. Что может быть более неудобным для начинающих, чем фрагмент кода, который не только не работает, но и не вызывает никаких исключений?
Арсений Мурзенко
@MainMa Точно мои мысли, но раньше я ошибался (когда выяснилось, что у них действительно была очень хорошая, но неочевидная причина), поэтому я решил спросить.
Роман Старков
2
Вау, я рада, что вы опубликовали это только потому, что впервые услышали об этом; и это определенно нарушает ПОЛА . Вы правы в том, что эти парни действительно знают, что делают, поэтому мне искренне любопытно, что за этим стоит причина ... Интересно, есть ли у нее более техническая причина, основанная на реализации Async, и как будут распространяться исключения? как дно , передаваемое сопрограмме ..
Джимми Хоффа

Ответы:

2

Что бы это ни стоило, документ, на который вы ссылаетесь, дает пример в качестве оправдания:

Task op1 = FooAsync(); 
Task op2 = BarAsync(); 
await op1; 
await op2;

В этом коде разработчик запускает две асинхронные операции для параллельного выполнения, а затем асинхронно ожидает каждой из них, используя новую функцию языка await ... [C] рассмотрим, что произойдет, если произойдет сбой как в op1, так и в op2. Ожидание op1 распространит исключение op1, и поэтому op2 никогда не будет ожидаться. В результате исключение op2 не будет соблюдаться, и процесс в конечном итоге завершится сбоем.

Чтобы облегчить разработчикам написание асинхронного кода на основе задач, .NET 4.5 изменяет поведение исключений по умолчанию для ненаблюдаемых исключений. Хотя ненаблюдаемые исключения по-прежнему будут вызывать событие UnobservedTaskException (если это не будет нарушением), процесс по умолчанию не завершится сбоем. Скорее, исключение в конечном итоге будет съедено после возникновения события, независимо от того, наблюдает ли обработчик события исключение.

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

Поведение настраивается - но, конечно, 99% разработчиков просто собираются использовать поведение по умолчанию, никогда не задумываясь об этой проблеме. Так что то, что они выбрали по умолчанию, имеет большое значение.


источник
Но вы делаете получить нормальное исключение для op1, не так ли? Если что один остается необработанным, он будет валить процесс, не так ли?
Тимви,
1
@ Тимви, насколько я понимаю, ни op1исключение, ни op2исключение не приведут к срыву программы. Преимущество в том, что у вас есть возможность наблюдать за обоими. Но если вы этого не сделаете, они оба будут проглочены. Хотя я могу ошибаться.
Я действительно удивлен тем, что им так важно позволить вам «наблюдать» за обоими. Если вы хотите «наблюдать» за ними, вы ловите их и сообщаете об их появлении через результат задания! ... Согласитесь с вашими рассуждениями, +1
Роман Старков
2

TL; DR - Нет , вы не должны просто тихо игнорировать исключения.


Давайте посмотрим на предположения.

  • Твоя слепая вера

Я научился верить, что многие решения в .NET были приняты людьми, которые действительно знают, что они делают, и, как правило, есть веская причина, по которой они решают. Но этот ускользает от меня.

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

Суть в том, что если ваш инстинкт говорит вам, что что-то может быть не так, то есть хороший шанс (и прошлый прецедент), что это неправильно.

  • Что это техническая проблема

Как обрабатывать исключения в этом случае является решением человеческого фактора, а не техническим решением. Проще говоря, исключением является ошибка. Сообщение об ошибке, даже если она плохо отформатирована, предоставляет важную информацию конечному пользователю. А именно, что-то пошло не так.

Рассмотрим этот гипотетический разговор между конечным пользователем и разработчиком.

Пользователь: приложение не работает.
Dev: Что сломано?
Пользователь: Я не знаю, я нажимаю на кнопку, и ничего не происходит.
Dev: Что вы подразумеваете под ничего не происходит?
Пользователь: Смотри, я нажимаю, я жду, и я жду, и я жду, и ничего ... это явно сломано.

Наш бедный, к счастью, гипотетический разработчик теперь должен выяснить, что пошло не так в цепочке событий. Где оно было?
Уведомление обработчика события -> Процедура обработки события -> Метод, инициируемый обработчиком -> Начало асинхронного вызова -> 7 уровней сети OSI -> Физическая передача -> Резервное копирование 7 уровней сети OSI -> Служба получения -> метод, вызываемый службой -> ... -> возвращаемый ответ, отправленный службой -> .... -> асинхронная квитанция -> обработка асинхронного ответа -> ...

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


После рассмотрения некоторых базовых предположений, я думаю, становится более понятным, почему тихое подавление исключений - плохая идея. Исключение и связанное с ним сообщение об ошибке являются ключевым показателем для пользователей, что что-то пошло не так. Даже если сообщение не имеет смысла для конечного пользователя, встроенная информация может быть полезна для разработчика, чтобы понять, что пошло не так. Если им повезет, сообщение даже приведет к решению.

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

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

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


источник