我有一个案例,我知道会发生,但非常稀缺。例如,每运行一万次代码,这可能会发生一次。
我可以通过简单的if
检查此案例,但此if
会多次运行而无法使用。
另一方面,我可以将代码放在try-catch块中,当发生特殊情况时,我会执行恢复所需的操作。
问题是哪一个更好?我知道一般来说,try-catch不应该用于已知的情况,因为开销问题以及应用程序逻辑不应该依赖catch代码,但运行if多次会有更多的性能问题。我使用这个小测试代码对此进行了测试:
static void Main(string[] args)
{
Stopwatch sc = new Stopwatch();
var list = new List<int>();
var rnd = new Random();
for (int i = 0; i < 100000000; i++)
{
list.Add(rnd.Next());
}
sc.Start();
DoWithIf(list);
sc.Stop();
Console.WriteLine($"Done with IFs in {sc.ElapsedMilliseconds} milliseconds");
sc.Restart();
DoWithTryCatch(list);
sc.Stop();
Console.WriteLine($"Done with TRY-CATCH in {sc.ElapsedMilliseconds} milliseconds");
Console.ReadKey();
}
private static int[] DoWithTryCatch(List<int> list)
{
var res = new int[list.Count ];
try
{
for (int i = 0; i < list.Count; i++)
{
res[i] = list[i];
}
return res;
}
catch
{
return res;
}
}
private static int[] DoWithIf(List<int> list)
{
var res = new int[list.Count - 1];
for (int i = 0; i < list.Count; i++)
{
if (i < res.Length)
res[i] = list[i];
}
return res;
}
此代码只是将大量数字复制到数量不足的数组中。在我的机器中检查数组边界,每次运行 210毫秒,同时使用try-catch,一旦在 190毫秒附近运行,就会遇到catch。
另外,如果你认为这取决于我的情况,我会在应用程序中获得推送通知,并检查我是否有该消息的主题。如果不是,我将获取并存储下一条消息的主题信息。在很少的主题中有很多消息。
答案 0 :(得分:3)
因此,可以准确地说,在您的测试中,if
选项比try...catch
选项慢20毫秒,循环次数为100000000次。
这相当于20 / 100,000,000 - 每次迭代 0.0000002毫秒。
你真的认为那种纳米优化是值得编写违反正确设计标准的代码吗?
异常是针对特殊情况,即您无法控制或无法提前测试的事情 - 例如,当您从数据库中读取数据并且连接终止于中间时 - 这样的事情。 对于可以使用简单代码轻松测试的事物使用异常 - 嗯,这是完全错误的。
例如,如果您在这两个选项之间表现出有意义的性能差异,那么您可以证明使用try...catch
代替if
是合理的 - 但这显然不是这里的情况。
因此,总结一下 - 使用if
,而不是try...catch
。
您应该为了清晰而设计代码,而不是为了提高性能。
编写代码,以最清晰的方式传达它正在实施的算法
设置性能目标并衡量代码的性能
如果您的代码不符合您的绩效目标,请找到瓶颈并对其进行处理
在设计代码时,不要浪费时间进行纳米优化。
答案 1 :(得分:2)
在你的情况下,你已经错过了明显的优化:如果你担心调用if
100.000次太多了...... 不?
private static int[] DoWithIf(List<int> list)
{
var res = new int[list.Count - 1];
var bounds = Math.Min(res.Length, list.Count)
for (int i = 0; i < bounds; i++)
{
res[i] = list[i];
}
return res;
}
所以我知道这只是一个测试案例,但答案是:如果你需要它,你可以根据需要进行优化。如果你在循环中有某些东西被认为是昂贵的,那么试着把它移出循环。 基于逻辑优化,而不是基于编译器结构。如果您要优化编译器结构,则不应该使用托管和/或高级语言进行编码。