C# 中的哈希表比 C++ 更快?

Posted

技术标签:

【中文标题】C# 中的哈希表比 C++ 更快?【英文标题】:Hash table faster in C# than C++? 【发布时间】:2010-12-26 05:59:07 【问题描述】:

这是我一直在调查的一个好奇心。在我一直运行的测试中,与 STL unordered_map 相比,.NET Dictionary 类的执行速度快得离谱,我不知道为什么。

(在我的机器上为 0.5 秒与 4 秒) (.NET 3.5 SP1 与 Visual Studio 2008 Express SP1 的 STL)

另一方面,如果我用 C# 和 C++ 实现自己的哈希表,C++ 版本的速度大约是 C# 版本的两倍,这很好,因为它强化了我的常识,即本机机器代码有时更快。 (见。我说“有时”。)我在两种语言中都是同一个人,我想知道微软的 C# 编码器有什么技巧可以玩微软的 C++ 编码器不能?我很难想象编译器如何自己发挥这些技巧,并经历优化应该看起来是任意函数调用的麻烦。

这是一个简单的测试,存储和检索整数。

C#:

const int total = (1 << 20);
int sum = 0;
Dictionary<int, int> dict = new Dictionary<int, int>();
for(int i = 0; i < total; i++)

    dict.Add(i, i * 7);


for(int j = 0; j < (1 << 3); j++)

    int i = total;
    while(i > 0)
    
        i--;
        sum += dict[i];
    

Console.WriteLine(sum);

C++:

const int total = (1 << 20);
int sum = 0;
std::tr1::unordered_map<int, int> dict;
for(int i = 0; i < total; i++)

    dict.insert(pair<int, int>(i, i * 7));


for(int j = 0; j < (1 << 3); j++)

    int i = total;
    while(i > 0)
    
        i--;
        std::tr1::unordered_map<int, int>::const_iterator found =
            dict.find(i);
        sum += found->second;
    

cout << sum << endl;

【问题讨论】:

C++ 版本的类型是否像 Dictionary 那样? 本机机器码比什么快?你认为 C# 的运行方式是什么? 你如何衡量性能? 好奇你是否在发布版本中运行代码。由于要执行大量额外检查,MS STL 实现在调试构建中的速度非常慢。 @imaginaryboy,MS 并不是唯一一个遭受这种痛苦的人。使用 XCode 从 Debug 切换到 Release 几乎使上述 C++ 代码的性能提高了一倍。 【参考方案1】:

您正在衡量显式内存管理的成本。更多统计数据可用here. 这是relevant too. 和Chris Sells' attempt 为 CLR 添加确定性终结是值得注意的。

【讨论】:

【参考方案2】:

在代码级别会有一些差异:无序映射采用一对这一事实会强制构造此类对象,而 C# 在 Add 中传递两个参数可能会更快。

另外一点是哈希表本身的实现:哈希函数的实现,或者说处理冲突的方式,会导致不同的性能模式。

加上对齐和缓存、某些算法的 JIT 友好性,以及比较两种不同语言的两种不同实现变得非常困难,您唯一可以比较的是手头的特定任务。尝试使用更少或更多元素,或者尝试随机访问元素而不是按顺序访问元素,您可能会看到截然不同的结果。

【讨论】:

【参考方案3】:

这两个版本是不等价的,您在 C++ while 循环的每次传递中都构造了一个迭代器。这会占用 CPU 时间并抛出您的结果。

【讨论】:

同意 - 尝试替换“dict.insert(pair(i, i * 7));”用“dict[i] = i * 7;”低一级的好。 那个,他们在 C# 版本中使用数组运算符和在 C++ 版本中使用 find() 方法。 @Glen:“数组运算符”是一种调用FindEntry 方法的语法便利。它没有速度优势。 @Ben,在我的 STL 版本中没有任何地方有 FindEntry 方法。此外,下标运算符和 find 方法的实现也完全不同,这使我相信它们的执行方式可能与另一种完全不同。我不确定应该是哪个,但是适当的性能测试应该很容易证明这一点 @Ben,如果您指的是 C# 下标运算符,那么很抱歉我选错了。但是,OP 应该尝试在两种实现中编写正确的代码,而不是将好的 C# 代码与平均 C++ 实现进行比较

以上是关于C# 中的哈希表比 C++ 更快?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 哈希表查询_进入哈希函数结界的世界

哈希表与字典:更快?

C ++中的哈希表?

C++ 有没有结合了数组和链表优点的容器?

在哈希表或排序列表中查找项目哪个更快?

在 C++ 中删除哈希表