Насколько дороже Исключение, чем возвращаемое значение?
Можно ли изменить этот код с возвращаемым значением и исключением:
public Foo Bar(Bar b)
{
if(b.Success)
{
return b;
}
else
{
throw n.Exception;
}
}
что дает отдельные исключения для успеха и неудачи
public Foo Bar(Bar b)
{
throw b.Success ? new BarException(b) : new FooException();
}
try
{
Bar(b)
}
catch(BarException bex)
{
return ex.Bar;
}
catch(FooException fex)
{
Console.WriteLine(fex.Message);
}
Ответы
Ответ 1
Бросок исключения определенно дороже, чем возврат значения. Но с точки зрения сырьевой стоимости трудно сказать, насколько дороже исключение.
При принятии решения о возвращаемом значении и исключении вы всегда должны учитывать следующее правило.
Используйте исключения только для исключительных обстоятельств
Они никогда не должны использоваться для общего потока управления.
Ответ 2
Используя приведенный ниже код, тестирование показало, что вызов + возврат без каких-либо исключений составлял около 1,6 микросекунды на итерацию, тогда как исключения (throw plus catch) добавляли около 4000 микросекунд каждый. (!)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DateTime start = DateTime.Now;
bool PreCheck = chkPrecheck.Checked;
bool NoThrow = chkNoThrow.Checked;
int divisor = (chkZero.Checked ? 0 : 1);
int Iterations = Convert.ToInt32(txtIterations.Text);
int i = 0;
ExceptionTest x = new ExceptionTest();
int r = -2;
int stat = 0;
for(i=0; i < Iterations; i++)
{
try
{
r = x.TryDivide(divisor, PreCheck, NoThrow);
}
catch
{
stat = -3;
}
}
DateTime stop = DateTime.Now;
TimeSpan elapsed = stop - start;
txtTime.Text = elapsed.TotalMilliseconds.ToString();
txtReturn.Text = r.ToString();
txtStatus.Text = stat.ToString();
}
}
class ExceptionTest
{
public int TryDivide(int quotient, bool precheck, bool nothrow)
{
if (precheck)
{
if (quotient == 0)
{
if (nothrow)
{
return -9;
}
else
{
throw new DivideByZeroException();
}
}
}
else
{
try
{
int a;
a = 1 / quotient;
return a;
}
catch
{
if (nothrow)
{
return -9;
}
else
{
throw;
}
}
}
return -1;
}
}
Итак, да, Исключения очень дороги.
И прежде чем кто-то скажет это, ДА, я тестировал это в режиме Release, а не только в режиме Debug. Попробуйте сам код и посмотрите, получаете ли вы значительно разные результаты.
Ответ 3
Исключение имеет две издержки: разогрев до страницы в инфраструктуре исключения - если не в памяти, а затем в кеш процессора - и стоимость заброса для сбора стека исключений, поиск обработчика исключений, возможно включение фильтров исключений, восстановление стек, вызывая блокировки завершения - все операции, которые среда выполнения, по дизайну, не оптимизирована для.
Таким образом, измерение стоимости метательных исключений может вводить в заблуждение. Если вы напишете цикл, который итеративно выбрасывает и ловит исключение, без большой работы между сайтом-броском и узлом catch, стоимость не будет такой большой. Тем не менее, это потому, что оно амортизирует затраты на разминку для исключений и что затраты труднее измерить.
Конечно, исключения не стоят ничего похожего на то, что они кажутся, если один основной опыт - это исключения, брошенные программами под отладчиком. Но они действительно стоят, и желательно проектировать библиотеки, в частности, чтобы исключения можно было избежать, когда это необходимо для оптимизации.
Ответ 4
Вы можете найти много полезной информации об этом в ответах на этот вопрос, включая один ответ с 45 up-votes Насколько медленны исключения .net?
Ответ 5
В настоящее время у меня возникают проблемы с поиском каких-либо документов для его поддержки, но имейте в виду, что когда вы генерируете исключение, С# должен генерировать трассировку стека с той точки, где вы его вызывали. Трассировки стека (и отражение вообще) далеко не свободны.
Ответ 6
Использование возвратов ошибок будет намного дороже, чем исключения - как только часть кода забудет проверить возврат ошибки или не сможет ее распространять.
Тем не менее, не забудьте использовать исключения для потока управления - используйте их только для указания, что что-то пошло не так.
Ответ 7
В недавнем реальном анализе производительности труда мы обнаружили, что тонны исключений на машинах с нижним концом оказали критическое влияние на производительность приложения, так что мы посвящаем несколько недель, чтобы пройти и настроить код, чтобы не бросать так много.
Когда я говорю о критически важном эффекте, он был на стадионе с двухъядерным процессором до 95% на одном ядре процессора, используемом приложением.
Ответ 8
Вы должны предпочесть Исключения по кодам ошибок и для условий ошибки, но не использовать исключения для нормального потока программы.
Исключения чрезвычайно тяжелые по сравнению с обычным рабочим потоком, я видел огромное снижение производительности приложения с помощью блока try-catch.
Ответ 9
Бросок исключения - относительно недорогая операция. Это улавливает их, что приводит к расходам из-за стеков, которые должны произойти, чтобы найти обработчики уловов, выполнить код в обработчиках catch, найти блоки finally, выполнить код в блоках finally и затем вернуться к исходному вызывающему.
Настоятельно рекомендуется не использовать исключения для потока управления. Использование кодов возврата для обозначения ошибок становится дорогостоящим с точки зрения "времени и материалов", поскольку в конечном итоге расходы на обслуживание будут покрыты.
Все это в стороне, ваши два примера не совпадают и даже не верны. Поскольку вы возвращаетесь b
, который имеет тип Bar
, ваш первый метод должен, вероятно, быть:
public Bar Foo(Bar b)
{
if(b.Success)
{
return b;
}
else
{
throw n.Exception;
}
}
который можно было бы переписать как:
public Bar Foo(Bar b)
{
if (!b.Success)
throw n.Exception;
return b;
}
Ответ 10
Как правило, я избегал этого из-за дорогостоящего характера исключения. Возможно, это не так уж плохо, если это не так часто происходит.
Однако почему бы просто не вернуть null? Тогда он станет следующим:
public Foo Bar(Bar b)
{
if(b.Success)
{
return b;
}
else
{
return null;
}
}
И затем всякий раз, когда вы вызываете Bar(), вы просто проверяете, чтобы возвращаемое значение не было null, прежде чем использовать значение. Это гораздо менее дорогостоящая операция. И я считаю это хорошей практикой, потому что это метод, который Microsoft использовал повсеместно во многих встроенных функциях .NET.
Ответ 11
Я видел много разных систем, где исключения считались признаком проблемы программного обеспечения, а также означало предоставление информации о событиях, ведущих к ней. Это всегда тяжело в системе. Однако существуют системы, в которых исключение не было исключительным, поскольку сам язык использовал одни и те же или подобные методы для возврата из подпрограммы и т.д. Таким образом, это сводится к тому, как исключения внедряются в язык и систему.
Я сделал измерения в java и в собственной системе, над которой я работаю прямо сейчас, и результаты были как ожидалось - исключительные исключения были (на 20-25%) дороже.
Это не должно быть правило. Интересно, например, как python стоит на этом. Я больше не занимаюсь разработкой python, поэтому я не собираюсь исследовать.
В качестве, возможно, интересных анекдотических доказательств можно привести следующее: в проприетарной системе я несколько лет назад работал над неумным использованием исключений для нарушений протокола, что привело к серьезным проблемам и сбоям в работе одной из наших производственных систем. Исключения были использованы для указания отсутствующего или поврежденного обязательного поля в сообщении, полученном извне. Все было хорошо до одного солнечного дня, когда какая-то менее квалифицированная компания произвела node, который при вводе в эксплуатацию вызвал массу неприятностей. Исключения должны были быть удалены, поскольку мы не смогли справиться с даже низким уровнем сигнализации из-за неисправности node. Ошибка также была на нашей стороне - вместо этого, чтобы следовать спецификации протокола, которая описывала, что делать с плохо отформатированными сообщениями (игнорировать и вызывать счетчик ошибок сигнализации), мы попытались обнаружить и отладить ошибку программного обеспечения во внешнем node.
Если бы исключения были менее дорогими, это не было бы такой большой проблемой.
Фактически во время тестирования безопасности в наши дни у меня всегда есть TC или несколько, которые делают именно это - генерируют большой объем ситуаций нарушения протокола. Если разработчики используют исключения для их обработки, система легко может быть поднята на колени. Когда это произойдет, я снова начну измерять разницу.