问题描述
我有一个应用程序,我使用了很多异常
。
最近我听说过例外成本
我的应用程序如下所示:
尝试
{
Function1();
Function2();
Function3();
Function4();
}
catch(Execption ex)
{
//我向用户返回发生在
//函数内的错误(ex)失败
}
我的每个功能1,2,3等看起来都像这样..
Void Function1()
{
//做某事...
//如果有事情失败
抛出新异常(因为bla bla而失败);
//做某事...
//如果有事情失败
抛出新异常(因为bla bla bla bla而失败);
//如果一切都可以,只要继续,不要抛出任何东西
}
这是不好的设计?
这会伤害我的应用程序性能吗?
当抛出异常时,它们会重建堆栈跟踪。这是相当昂贵的。如果可以的话,尝试防止这样一个已知的错误条件(这里是C风格):
public static const int INVERSE_DIVISION_BY_ZERO = -1; //任何不正确操作的值都可以执行
public int Inverse(int a)
{
if(a!= 0)
{
返回1 / a;
}
返回INVERSE_DIVISION_BY_ZERO;
}
现在,这个例子是我所知道的丑陋。实际上从第一个测试开始:
if(a!= 0)
{
b =反(a);
}
现在要稍后测试:
b =反(a);
如果(b!= Inverse.INVERSE_DIVISION_BY_ZERO)
{
//安全去
}
这是否有意义?不,这个例子很差。但是这表明有最少的测试要保证代码执行安全。如果以前没有完成,它必须在以后完成,但不能真正避免。
异常应抛出错误条件,例如等中的CD那样控制它们。当你已经知道代码如何失败,阻止它!
我想添加:
常见的C#实践是倾向于清除可读的代码过早优化,并且我分享这个愿景。
但是不是意味着异常应该被故意抛出。有些情况下,有意的投掷是完美的,例如:
枚举性别
{
未指定,
男性,
女性
}
//以后的代码
开关(性别)
{
case Gender.Unspecified:
// handle
break;
case Gender.Male:
// handle
break;
case Gender.Female:
// handle
break;
default:
throw new ArgumentException(string.Format(Unrecognized gender(was {0}),(int)gender));
}
未定义的性别不能呈现为一个字符串,因为它没有定义。它将被渲染为一个int值。
现在这个例子在我看来是一个可读的代码,当在未来的时间里修改了性别枚举时,这个代码也很强大。至少它会告诉开发人员他忘了一些东西...
另一个例子是这样的:
<$ p $ (i = 0; i< values.length; i ++)
{
values [i] = 1 / values [i];
}
// B:缓慢的表现,先测试
(i = 0; i< values.length; i ++)
{
if(values [i]!= 0)
{
values [i] = 1 / values [i];
}
}
当值[i]
是0 A 将失败,而 B 将忽略阵列中的该位置。现在我想知道这个:
- 这个数组对未处理的点有用吗?也许应该在那个时候被抛弃;
- 测试而不是抛出一个异常更好吗?
- 如果
0
很少发生每1000年一次(真的)?这就像说永远不会,而是基于概率估计。 - 可能在每个周期中测试一些最可能不会发生的事情是浪费...
-
如果有固体数据显示错误条件极为罕见,应该使用例外处理,因为测试的平均成本会更高
这并不意味着您不处理异常状态,它只是意味着您以非有效的方式处理它,因为它很少见,事先测试是昂贵的
编辑:添加错误条件
编辑2:添加了一些更多想法
I have an App where I use a lot of Exceptions
.
Recently I heard that Exceptions cost a lot in terms of performance.
My App looks like this:
Try
{
Function1();
Function2();
Function3();
Function4();
}
catch(Execption ex)
{
//I return to the user the error (ex) that happen inside the
//function that fails
}
Each of my functions 1,2,3 etc look similar to this..
Void Function1()
{
//Do something...
//If something fail
Throw New Exception("Fails because bla bla");
//Do something...
//If something fail
Throw New Exception("Fails because bla bla bla bla");
//If everything its ok, just continue without throwing anything
}
Is this bad design?
Will this hurt my App performance?
When exceptions are thrown they rebuilt the stack trace among other things. This is pretty costly. If you can, try to prevent a known error condition like this (here C-style):
public static const int INVERSE_DIVISION_BY_ZERO = -1; // any value not possible on correct operation will do
public int Inverse(int a)
{
if (a != 0)
{
return 1 / a;
}
return INVERSE_DIVISION_BY_ZERO;
}
Now, this example is ugly I know. It doesn't help much.
In fact from testing first:
if (a != 0)
{
b = Inverse(a);
}
It is now a matter of testing later:
b = Inverse(a);
if (b != Inverse.INVERSE_DIVISION_BY_ZERO)
{
// safe to go
}
Does this make sense? No. The example is quite poor. But it shows that there is a minimum amount of testing to do to keep code execution safe. If it's not done before, it has to be done later, but can't really be avoided.
Exceptions should be thrown for error conditions that are exceptional in a sense that you can't control them like no CD in drive and similar. When you already know how the code fails, prevent it!
I want to add this:
The common C# practice is to favor clean, readable code over premature optimization, and I share this vision.
But this does not mean that Exceptions should be deliberately thrown. There are cases where intentional throwing makes perfect sense, for example:
enum Gender
{
Unspecified,
Male,
Female
}
// later in the code
switch (gender)
{
case Gender.Unspecified:
// handle
break;
case Gender.Male:
// handle
break;
case Gender.Female:
// handle
break;
default:
throw new ArgumentException(string.Format("Unrecognized gender (was {0})", (int)gender));
}
The undefined gender can't be rendered as a string because it is not defined. It will be rendered as an int value, instead.
Now this example is in my opinion clean readable code that is also robust when the Gender enum is modified in future times. At least it will tell the developer that he forgot something...
Another example is this:
// A: high performance, let it throw
for (i = 0; i < values.length; i++)
{
values[i] = 1 / values[i];
}
// B: slow performance, test first
for (i = 0; i < values.length; i++)
{
if (values[i] != 0)
{
values[i] = 1 / values[i];
}
}
When values[i]
is 0 A will fail while B will ignore that spot in the array. Now I wonder about this:
- is the array useful with unhandled spots? maybe it should be thrown away at that point;
- is it really more performant to test instead of throw an exception?
- what if
0
is so seldom it happens once every 1000 years (really)? That's like saying never, but based on probabilistic estimations. - maybe testing in each cycle for something that most probably will not happen is a waste...
If there is solid data to show that error conditions are extremely rare they should be handled with exceptions, because testing will cost much more on the average.
This doesn't mean you don't handle the exceptional state, it just means you handle it in a non-efficient way because it's rare and testing beforehand is costly.
EDIT: added error condition
EDIT 2: added some more thoughts
这篇关于使用异常结束函数是不是很糟糕?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!