为什么检查字典是否包含关键字比在不包含关键字的情况下捕获异常更快;t

本文关键字:关键字 包含 捕获异常 情况下 字典 检查 是否 为什么 | 更新日期: 2023-09-27 18:09:55

想象一下代码:

public class obj
{
    // elided
}
public static Dictionary<string, obj> dict = new Dictionary<string, obj>();

方法1

public static obj FromDict1(string name)
{
    if (dict.ContainsKey(name))
    {
        return dict[name];
    }
    return null;
}

方法2

public static obj FromDict2(string name)
{
    try
    {
        return dict[name];
    }
    catch (KeyNotFoundException)
    {
        return null;
    }
}

我很好奇这两个函数的性能是否有差异,因为第一个函数应该比第二个函数慢——考虑到它需要检查两次字典是否包含值,而第二个功能只需要访问字典一次,但哇,它实际上相反:

1000 000个值的循环(10万个现有值和90万个不存在值(:

第一个功能:306毫秒

第二个功能:20483毫秒

为什么?

编辑:正如你在这个问题下面的评论中所注意到的,如果有0个不存在的键,第二个函数的性能实际上比第一个略好。但一旦至少有一个或多个不存在的密钥,第二个密钥的性能就会迅速下降。

为什么检查字典是否包含关键字比在不包含关键字的情况下捕获异常更快;t

一方面,抛出异常本身就很昂贵,因为堆栈必须展开等等。
另一方面,通过关键字访问字典中的值很便宜,因为这是一个快速的O(1(运算。

BTW:正确的方法是使用TryGetValue

obj item;
if(!dict.TryGetValue(name, out item))
    return null;
return item;

这只访问字典一次,而不是两次
如果你真的想在密钥不存在的情况下只返回null,那么上面的代码可以进一步简化:

obj item;
dict.TryGetValue(name, out item);
return item;

这是有效的,因为如果不存在具有name的密钥,则TryGetValueitem设置为null

字典是专门为进行超快速键查找而设计的。它们被实现为哈希表,条目越多,相对于其他方法就越快。只有当您的方法未能完成您设计的任务时,才应该使用异常引擎,因为它是一个大型对象集,为您提供了大量处理错误的功能。我曾经构建过一个完整的库类,所有的东西都被try-catch块包围过一次,看到调试输出中包含600多个异常中的每一个都有一行,我感到非常震惊!