Надо мне выбрать способ которым я буду сообщать вышестоящим (в иерархии вложенности) методам об ошибках возникающих во вложенных методах. И приходит на ум два варианта: 1) возвращать значение или объект описывающий результат операции; 2) генерировать исключение. С одной стороны с исключениями как-то проще, поймал его где тебе надо и обрабатывай. С другой стороны волнует вопрос производительности, т.к. вложенные методы будут регулярно выкидывать исключения сообщая об ошибках, т.к. по другому никак нельзя. Так вот насколько будет отличаться производительность при сравнении двух этих подходов
Здравствуйте, Cynic, Вы писали:
C>Надо мне выбрать способ которым я буду сообщать вышестоящим (в иерархии вложенности) методам об ошибках возникающих во вложенных методах. И приходит на ум два варианта: 1) возвращать значение или объект описывающий результат операции; 2) генерировать исключение.
Отлавливаемые исключения можно использовать ровно в трёх случаях:
1. Объект не изменяет внешнее состояние до возникновения ошибки и не используется сам после неё. В идеале это static-методы или immutable-объекты.
2. Вы единолично владеете всем кодом по стеку от броска исключения до обработчика ошибок _и_ этот код умеет корректно откатывать поломанное состояние при исключениях.
3. У вас есть рабочий фреймворк для in-memory-транзакций и все бизнес-сущности его поддерживают.
Во всех остальных вариантах говорить о производительности смысла нет вообще — у вас потенциально поломанный код.
Дальше для каждого из вариантов всё зависит от требований по производительности (бросать исключения в hot path — плохая идея), от частоты бросания исключения и от сложности корректной реализации того же, но без исключений.
Нюанс раз: пропущенный if(hasError) return намного хуже проглоченного исключения, т.к. найти его нереально.
Нюанс два: вариант с OptionOrError<T> по производительности вполне может оказаться хуже, чем одно исключение на миллион итераций.
Здравствуйте, Cynic, Вы писали:
C> насколько будет отличаться производительность при сравнении двух этих подходов
В эпоху bloatware и всяких тормозных VM, такой вопрос становится непрофессиональным. Правильно спрашивать так: для бизнес нужд достаточно ли будет производительности "на исключениях"?
Пишешь софт, запускаешь типичную нагрузку, меряешь.
Здравствуйте, seregaa, Вы писали:
S>>Во всех остальных вариантах говорить о производительности смысла нет вообще — у вас потенциально поломанный код.
S>Любой боле-менее сложный код является потенциально поломанным (согласно аксиоме о невозможности программ без ошибок).
Любой stateless код по определению устойчив к исключениям, вне зависимости от его сложности. Причём нас интересует не внутренняя реализация, а гарантированное отсутствие побочных эффектов в момент выхода из тела метода.
S>Вариант с кодами возврата тоже _потенциально_ поломанный, поскольку нет гарантии, что коды везде будут правильно анализироваться.
Есть гарантия, что не будет, скорее.
Та же проблема что и с nullable references. С исключениями сообразили сразу, с not null — через семнадцать лет.
Здравствуйте, Cynic, Вы писали:
C>Надо мне выбрать способ которым я буду сообщать вышестоящим (в иерархии вложенности) методам об ошибках возникающих во вложенных методах. И приходит на ум два варианта: 1) возвращать значение или объект описывающий результат операции; 2) генерировать исключение. С одной стороны с исключениями как-то проще, поймал его где тебе надо и обрабатывай. С другой стороны волнует вопрос производительности, т.к. вложенные методы будут регулярно выкидывать исключения сообщая об ошибках, т.к. по другому никак нельзя. Так вот насколько будет отличаться производительность при сравнении двух этих подходов
1) Можно померить и то и то;
2) Навскидку вариант с исключениями будет подольше, т.к. runtime будет каждый раз сканировать таблицу обработчиков исключения (тут может есть какие оптимизации со стороны runtime );
3)преимущества исключения -- built-in ифраструктура, а в первом случае придется все самому;
Если вложенность методов большая, то искл. лучше, иначе -- первый вариант вполне пригоден.
Здравствуйте, Sharov, Вы писали:
S>Навскидку вариант с исключениями будет подольше, S>Если вложенность методов большая, то искл. лучше, иначе -- первый вариант вполне пригоден.
Ну вот специально провоцируете на "в жизни всё не так как на самом деле", да?
I think this scenario is rather misleading. On my system (an AMD Athlon 64 2.2 gHz Server 2003, SP1) on .NET 2.0 (32 bit, release build) this benchmark produces about 29,000 exceptions/sec. This means it takes on average about 35 microseconds to throw/catch the exception.
Compared to an hour, that’s tiny. But compared to returning an error code, it’s about 35,000 times more expensive.
Compared to simple system calls (eg. SetEvent, it’s about 70-100 times more expensive.)
It’s also several times slower than writing 128 bytes to a file (where the file write is completed in the FS cache).
To evaluate the 200/hr scenario, one has to ask several other questions.Do these 200/hr happen to coincide with the 200 transactions/ hr that the application processes? If so, what is the time with and without the exception. If it takes 35 us to process a tranaction without the exception, and 70 with the exception, it’s doubled your processing time. That’s a big difference.
I don’t that the 200/hr sheds much light on the cost of exceptions.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Sharov, Вы писали:
S>>Навскидку вариант с исключениями будет подольше, S>>Если вложенность методов большая, то искл. лучше, иначе -- первый вариант вполне пригоден. S>Ну вот специально провоцируете на "в жизни всё не так как на самом деле", да?
Не согласен. Все ссылки десятилетней давности. Это раз. Железо стало быстрее, в clr многое поменялось и улучлось (надеюсь на это ). Это два.
Фундаментально обработка искл. -- линейный поиск обработчика , снизу вверх. Ничего ресурсоемкого тут нет. С трудом я представляю сценарий ТС, но все же с нуля разрабатывать похожую инфраструктуру как-то глупо. Что делать если надо вернуть ошибку, которую сможет понять метод на 10 строчек вверх по стеку?
Здравствуйте, Sharov, Вы писали:
S>Не согласен. Все ссылки десятилетней давности. Это раз. Железо стало быстрее, в clr многое поменялось и улучлось (надеюсь на это ). Это два.
Два — не угадал
Другое дело, что это в принципе не важно. Не в том направлении думаешь. Снова цитата, снова Джо Скит:
Basically, exceptions shouldn't happen often unless you've got significant correctness issues, and if you've got significant correctness issues then performance isn't the biggest problem you face.
Подробнее — первые две ссылки в предыдущем сообщении.
Про "железо стало быстрее" — есть идеи, как выигрыш на порядок (оптимист, угу) поможет справиться с
This means it takes on average about 35 microseconds to throw/catch the exception. ... compared to returning an error code, it’s about 35,000 times more expensive.
?
S>С трудом я представляю сценарий ТС, но все же с нуля разрабатывать похожую инфраструктуру как-то глупо. Что делать если надо вернуть ошибку, которую сможет понять метод на 10 строчек вверх по стеку?
У топикстартера не "вернуть ошибку", а control flow на исключениях. Не самая полезная вещь, особенно в нагруженном коде.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Sharov, Вы писали:
S>>Не согласен. Все ссылки десятилетней давности. Это раз. Железо стало быстрее, в clr многое поменялось и улучлось (надеюсь на это ). Это два. S>Два — не угадал S>Другое дело, что это в принципе не важно. Не в том направлении думаешь. Снова цитата, снова Джо Скит: S>
S>Basically, exceptions shouldn't happen often unless you've got significant correctness issues, and if you've got significant correctness issues then performance isn't the biggest problem you face.
S>Подробнее — первые две ссылки в предыдущем сообщении.
Замечательные правильные слова для книжки. Не для жизни.
S>Про "железо стало быстрее" — есть идеи, как выигрыш на порядок (оптимист, угу) поможет справиться с S>
S>This means it takes on average about 35 microseconds to throw/catch the exception. ... compared to returning an error code, it’s about 35,000 times more expensive.
?
Я не спорю, что это лучший вариант вообще. Но по сравнению с альтернативой, когда возвращается код ошибки, анализируется пред. методом, если не может обработать возвращает пред. методу и т.д. Чем это лучше исключений, учитывая что это аут оф зе бокс?
S>>С трудом я представляю сценарий ТС, но все же с нуля разрабатывать похожую инфраструктуру как-то глупо. Что делать если надо вернуть ошибку, которую сможет понять метод на 10 строчек вверх по стеку? S>У топикстартера не "вернуть ошибку", а control flow на исключениях. Не самая полезная вещь, особенно в нагруженном коде.
Вот точно не уверен, но вроде в руби есть механизм нелокального перехода (возврата) из метода, а-ля исключения (это не совсем корутины, просто можно вернуться на n методов выше по стеку). Вполне себе язык для нагруженных вычислений. Гит на рубях вроде бы работает.
Здравствуйте, Sharov, Вы писали:
S>Замечательные правильные слова для книжки. Не для жизни.
Охх, вот примерно половина моей нынешней работы — выматывающее, нудное, бесконечно раздражающее исправление идиотских ошибок весьма умных людей, которые не посчитали нужным изучить матчасть, гадлайны и оф. документацию. Так что я просто притворюсь, что не заметил этот довод
S>Я не спорю, что это лучший вариант вообще. Но по сравнению с альтернативой, когда возвращается код ошибки, анализируется пред. методом, если не может обработать возвращает пред. методу и т.д. Чем это лучше исключений, учитывая что это аут оф зе бокс?
Неправильно вопрос ставишь. Ситуация "я собираюсь использовать фичу не по назначению и оправдываю это жизненной необходимостью" — это всегда (без исключений) следствие XY problem aka проблема мангустов в почтовом ящике
У тебя получаются ровно два варианта — или исключения, или возвращаемый код ошибки. Tester-Doer / TryXxx — не? Переписать код так, чтобы результат не приходилось протаскивать — тож низзя? Или врубить strict null policy в решарпере и возвращать null в качестве "нишмогла"? Я уж не говорю про восьмой шарп с non-nullable references. Вариантов всегда больше одного, главное не переть вперёд, если что-то не получается, а проверить логику на несколько шагов назад.
S>Вот точно не уверен, но вроде в руби есть механизм нелокального перехода (возврата) из метода, а-ля исключения (это не совсем корутины, просто можно вернуться на n методов выше по стеку). Вполне себе язык для нагруженных вычислений. Гит на рубях вроде бы работает.
Вот только мы не про ruby говорим, а про шарп и его реализацию исключений поверх SEH.
Здравствуйте, Sinix, Вы писали:
S>У тебя получаются ровно два варианта — или исключения, или возвращаемый код ошибки. S>Tester-Doer / TryXxx — не?
Вызовы Tester-Doer / TryXxx тоже придется через все уровни протаскивать.
Как иначе передать наверх инфу о том, что где то в кишках один из TryXxx навернулся?
S>Переписать код так, чтобы результат не приходилось протаскивать — тож низзя?
Выглядит очень заманчиво. Посмотреть бы на практическую реализацию.
S>Или врубить strict null policy в решарпере и возвращать null в качестве "нишмогла"? Я уж не говорю про восьмой шарп с non-nullable references.
null — тот же код возврата, только информации несет меньше. Да, гарантия проверки повышается, но функциональность ухудшается.
S>Вариантов всегда больше одного, главное не переть вперёд, если что-то не получается, а проверить логику на несколько шагов назад.
Все говорят, что есть другие варианты, но по факту выглядят они ущербно. Я не говорю, что их нет. Может кто то поделится?
Здравствуйте, Sharov, Вы писали:
S>Замечательные правильные слова для книжки. Не для жизни.
Для жизни слова тоже замечательные. Это одно из тех правил, которое нужно выбить в камне и повесить у входа — никогда не использовать логику на исключениях. И дело не только в перформансе. Та же отладка тоже заметно осложняется — я в свое время у antlr наелся, они в парсере логику откатов на исключениях реализуют.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Sharov, Вы писали:
S>>Замечательные правильные слова для книжки. Не для жизни.
AVK>Для жизни слова тоже замечательные. Это одно из тех правил, которое нужно выбить в камне и повесить у входа — никогда не использовать логику на исключениях. И дело не только в перформансе. Та же отладка тоже заметно осложняется — я в свое время у antlr наелся, они в парсере логику откатов на исключениях реализуют.
ТС не control flow на искл. делает, а обработку ошибок:
Надо мне выбрать способ которым я буду сообщать вышестоящим (в иерархии вложенности) методам об ошибках возникающих во вложенных методах.
Искл. для этого и создавались. И как первый прототип решения задачи вполне подходит.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Sharov, Вы писали:
S>>Замечательные правильные слова для книжки. Не для жизни. S>Охх, вот примерно половина моей нынешней работы — выматывающее, нудное, бесконечно раздражающее исправление идиотских ошибок весьма умных людей, которые не посчитали нужным изучить матчасть, гадлайны и оф. документацию. Так что я просто притворюсь, что не заметил этот довод
В нашем деле просто изучить, почитать гадлайны и оф. документацию не помогает. Learning by doing(c). Времени на это не всегда хватает.
S>>Я не спорю, что это лучший вариант вообще. Но по сравнению с альтернативой, когда возвращается код ошибки, анализируется пред. методом, если не может обработать возвращает пред. методу и т.д. Чем это лучше исключений, учитывая что это аут оф зе бокс?
S>Неправильно вопрос ставишь. Ситуация "я собираюсь использовать фичу не по назначению и оправдываю это жизненной необходимостью" — это всегда (без исключений) следствие XY problem aka проблема мангустов в почтовом ящике
Откройте для себя нестандартные решения, подход к задачам. В первую очередь Вы инженер,а уже потом программист. Собрать что-то из гамна и палок, в условиях временного цейтнота и других ограничений не всегда плохая идея. А уж если речь идет о сборке прототипа...
S>У тебя получаются ровно два варианта — или исключения, или возвращаемый код ошибки. Tester-Doer / TryXxx — не? Переписать код так, чтобы результат не приходилось протаскивать — тож низзя? Или врубить strict null policy в решарпере и возвращать null в качестве "нишмогла"? Я уж не говорю про восьмой шарп с non-nullable references. Вариантов всегда больше одного, главное не переть вперёд, если что-то не получается, а проверить логику на несколько шагов назад.
Выше уже написали -- как протаскивать ошибку? Если обработчик на 10 уровней сверху.
S>>Вот точно не уверен, но вроде в руби есть механизм нелокального перехода (возврата) из метода, а-ля исключения (это не совсем корутины, просто можно вернуться на n методов выше по стеку). Вполне себе язык для нагруженных вычислений. Гит на рубях вроде бы работает. S>Вот только мы не про ruby говорим, а про шарп и его реализацию исключений поверх SEH.
Да и не про нагрженные приложения тоже, во всяко случае ТС об этом не упоминал. Если только не явно.
S> а про шарп и его реализацию исключений поверх SEH.
Дураки какиета. Не чтобы взять и изучить матчасть и документацию, косяки явы и т.п. Взяли и запили на основе сущ. механизма. И оставили все как есть.
Здравствуйте, Sharov, Вы писали:
S>В нашем деле просто изучить, почитать гадлайны и оф. документацию не помогает. Learning by doing(c). Времени на это не всегда хватает.
Learning by doing не работает с проектированием. Нужен склад мышления отличный и от менеджерского и от девелоперского. Не, личное кладбище проектов здорово вправляет мозги, но выходит дороговато
S>>Неправильно вопрос ставишь. Ситуация "я собираюсь использовать фичу не по назначению и оправдываю это жизненной необходимостью" — это всегда (без исключений) следствие XY problem aka проблема мангустов в почтовом ящике
. S>Откройте для себя нестандартные решения, подход к задачам.
"я собираюсь использовать фичу не по назначению" и "нестандартные решения" — несколько разные вещи
В нашей ситуации нестандартное решение не нужно вообще. Смотрим:
Выше уже написали -- как протаскивать ошибку? Если обработчик на 10 уровней сверху.
Проблема тут явно не в самой обработке, а уровнем выше, в дубовой архитектуре, которая течёт абстракциями на десять уровней вверх. Серьёзно, у тебя цепочка из 10 нетривиальных методов и все они спроектированы с учётом неявного контракта "если не распарсил проблему, тут может быть вот такое вот исключение"? Ну изврат же, проще задокументировать контракт через "SomeResult<T>", чем объяснять каждому девелоперу в команде про "вот этот метод только через try-catch вызывать"
S>В первую очередь Вы инженер,а уже потом программист.
Где-то тут должны быть семь взаимно перпендикулярных линий, одна в форме котёнка Не, из принципа извратиться и не так можно, главное забить на то, что топикстартер ищет решение для продакшна.
S>Дураки какиета. Не чтобы взять и изучить матчасть и документацию, косяки явы и т.п. Взяли и запили на основе сущ. механизма. И оставили все как есть. Изучили, внезапно (вторая ссылка закрывает вопрос полностью). Результат — в реализации и гадлайнах. Ссылки уже давал, если есть _конкретный_ сценарий, где нужно городить control flow именно на исключениях — не вопрос, с интересом посмотрю.
Здравствуйте, Sharov, Вы писали:
AVK>>Для жизни слова тоже замечательные. Это одно из тех правил, которое нужно выбить в камне и повесить у входа — никогда не использовать логику на исключениях. И дело не только в перформансе. Та же отладка тоже заметно осложняется — я в свое время у antlr наелся, они в парсере логику откатов на исключениях реализуют.
S>ТС не control flow на искл. делает, а обработку ошибок:
Определение ситуации как ошибочной — в немалой степени субъективно. А вот заявленная частота, с которой ошибки случаются наводит на определенные мысли.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Sharov, Вы писали:
S>>В нашем деле просто изучить, почитать гадлайны и оф. документацию не помогает. Learning by doing(c). Времени на это не всегда хватает. S>Learning by doing не работает с проектированием. Нужен склад мышления отличный и от менеджерского и от девелоперского. Не, личное кладбище проектов здорово вправляет мозги, но выходит дороговато
Блин, весьма спорное утверждение. С одной стороны верно -- это дорого (в деньгах). С другой стороны, как еще становится проектировщиком? Ну читаю я гайдланы и документацию по исключениям, но это капля в море. За склад мышления не скажу, но навыки разработчика нужно точно, ибо надо понимать ограничения, т.е. ограничения железа.
S>>>Неправильно вопрос ставишь. Ситуация "я собираюсь использовать фичу не по назначению и оправдываю это жизненной необходимостью" — это всегда (без исключений) следствие XY problem aka проблема мангустов в почтовом ящике
. S>>Откройте для себя нестандартные решения, подход к задачам. S>"я собираюсь использовать фичу не по назначению" и "нестандартные решения" — несколько разные вещи
Безусловно, но в некоторых контекстах их невозможно различить.
S>В нашей ситуации нестандартное решение не нужно вообще. Смотрим: S>
S>Выше уже написали -- как протаскивать ошибку? Если обработчик на 10 уровней сверху.
S>Проблема тут явно не в самой обработке, а уровнем выше, в дубовой архитектуре, которая течёт абстракциями на десять уровней вверх. Серьёзно, у тебя цепочка из 10 нетривиальных методов и все они спроектированы с учётом неявного контракта "если не распарсил проблему, тут может быть вот такое вот исключение"? Ну изврат же, проще задокументировать контракт через "SomeResult<T>", чем объяснять каждому девелоперу в команде про "вот этот метод только через try-catch вызывать"
SomeResult<T> может иметь смысл для метода на десять позиций выше по стеку. Для неявного try-catch можно какой-нибудь AOP применить. Хотя это уже перебор...
S>>В первую очередь Вы инженер,а уже потом программист. S>Где-то тут должны быть семь взаимно перпендикулярных линий, одна в форме котёнка Не, из принципа извратиться и не так можно, главное забить на то, что топикстартер ищет решение для продакшна.
S>Ссылки уже давал, если есть _конкретный_ сценарий, где нужно городить control flow именно на исключениях — не вопрос, с интересом посмотрю.
Могу ошибаться, но исключения родились как частный случай подобного control flow.
Здравствуйте, Sharov, Вы писали:
S>Блин, весьма спорное утверждение. С одной стороны верно -- это дорого (в деньгах). С другой стороны, как еще становится проектировщиком? Ну читаю я гайдланы и документацию по исключениям, но это капля в море.
Зато очень ценная капля. А еще надо постоянно изучать чужой код, хотя бы на уровне API, и задавать себе вопросы, почему так а не иначе.
Кроме того, есть ряд областей, где без бекграунда у тебя мало что получится, сколько ты не doing. К примеру, те кто не знаком с теорией формальных языков и азами парсинга таких чудовищ городят при решении этой задачи. doing не помогает.
S>>Ссылки уже давал, если есть _конкретный_ сценарий, где нужно городить control flow именно на исключениях — не вопрос, с интересом посмотрю. S>Могу ошибаться, но исключения родились как частный случай подобного control flow.
Ни в коей мере. Видишь ли, исключения совсем не зря так обозвали. Они нужны не просто для обработки ошибок, а для обработки исключительных ситуаций. Т.е. это когда "Шеф, все пропало! Все пропало! Гипс снимают, клиент уезжает! ... Я убью его!" А когда вдруг возникают какие то коды возврата и обработка на 10 методов вверх по стеку, то как то это не очень на исключительную ситуацию похоже.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, Sharov, Вы писали:
S>>>Замечательные правильные слова для книжки. Не для жизни.
AVK>>Для жизни слова тоже замечательные. Это одно из тех правил, которое нужно выбить в камне и повесить у входа — никогда не использовать логику на исключениях. И дело не только в перформансе. Та же отладка тоже заметно осложняется — я в свое время у antlr наелся, они в парсере логику откатов на исключениях реализуют.
S>ТС не control flow на искл. делает, а обработку ошибок: S>
S>Надо мне выбрать способ которым я буду сообщать вышестоящим (в иерархии вложенности) методам об ошибках возникающих во вложенных методах.
S>Искл. для этого и создавались. И как первый прототип решения задачи вполне подходит.
Если событие происходит регулярно и ожидаемо, то это уже не исключительная ситуация.
вложенные методы будут регулярно выкидывать исключения сообщая об ошибках