为什么STL中的set_intersection这么慢?

时间:2009-06-29 16:54:18

标签: c# c++ performance stl intersection

我在STL中使用set_intersection交叉一组100,000个数字和一组1,000个数字,并且花费21秒,在C#中花费11ms。

C ++代码:

int runIntersectionTestAlgo()
{   

    set<int> set1;
    set<int> set2;
    set<int> intersection;


    // Create 100,000 values for set1
    for ( int i = 0; i < 100000; i++ )
    {
        int value = 1000000000 + i;
        set1.insert(value);
    }

    // Create 1,000 values for set2
    for ( int i = 0; i < 1000; i++ )
    {
        int random = rand() % 200000 + 1;
        random *= 10;

        int value = 1000000000 + random;
        set2.insert(value);
    }

    set_intersection(set1.begin(),set1.end(), set2.begin(), set2.end(), inserter(intersection, intersection.end()));

    return intersection.size(); 
}

C#代码:

static int runIntersectionTest()
    {
        Random random = new Random(DateTime.Now.Millisecond);

        Dictionary<int,int> theMap = new Dictionary<int,int>();

        List<int> set1 = new List<int>();
        List<int> set2 = new List<int>();

            // Create 100,000 values for set1
            for ( int i = 0; i < 100000; i++ )
            {
                int value = 1000000000 + i;
                set1.Add(value);
            }

            // Create 1,000 values for set2
            for ( int i = 0; i < 1000; i++ )
            {
                int value = 1000000000 + (random.Next() % 200000 + 1);
                set2.Add(value);
            }

            // Now intersect the two sets by populating the map
        foreach( int value in set1 )
            {
                theMap[value] = 1;
            }

            int intersectionSize = 0;

        foreach ( int value in set2 )
        {
            int count;
            if ( theMap.TryGetValue(value, out count ) )
            {
                intersectionSize++;
                theMap[value] = 2;
            }
            }

            return intersectionSize;
    }
}

5 个答案:

答案 0 :(得分:8)

一些事情会使你的两个例子更具可比性。

首先,您在STL中的示例不太正确,因为有一件事情应该按升序排序(在STL中说“严格的弱排序”)。

其次,你使用STL中作为树实现的“集合”,而不是作为链表的“列表”。随机插入集合比插入列表末尾更昂贵。

尝试在C ++示例中使用一个int列表,并首先对列表进行排序(否则设置inersection将无法正常工作),我认为您会看到更有利的结果。

答案 1 :(得分:5)

我在我的linux盒子上运行了你的C ++代码

$ time ./test

real    0m0.073s
user    0m0.060s
sys     0m0.003s

21s对我来说意味着你编译时没有优化。如果您使用MSVC,请确保已列出  编译定义中的_SECURE_SCL=0(参见msdn)。否则所有STL迭代器操作都会变慢。

答案 2 :(得分:2)

在这个古老的3GHz Pentium 4上,我在整个runIntersectionTestAlgo函数中得到2734毫秒,在调试版本中禁用了优化。我用VS2008 SP1编译。

如果我启用优化,我会得到93毫秒。

这是我的代码:

#include <set>
#include <algorithm>

using namespace std;

int runIntersectionTestAlgo()
{   

    set<int> set1;
    set<int> set2;
    set<int> intersection;


    // Create 100,000 values for set1
    for ( int i = 0; i < 100000; i++ )
    {
        int value = 1000000000 + i;
        set1.insert(value);
    }

    // Create 1,000 values for set2
    for ( int i = 0; i < 1000; i++ )
    {
        int random = rand() % 200000 + 1;
        random *= 10;

        int value = 1000000000 + random;
        set2.insert(value);
    }

    set_intersection(set1.begin(),set1.end(), set2.begin(), set2.end(), inserter(intersection, intersection.end()));

    return intersection.size(); 
}

#include <windows.h>
#include <iostream>

int main(){
    DWORD start = GetTickCount();

    runIntersectionTestAlgo();

    DWORD span = GetTickCount() - start;

    std::cout << span << " milliseconds\n";
}

禁用_SECURE_SCL对于版本构建没有任何影响,它仍然在100毫秒左右徘徊。

当然,

GetTickCount并不理想,但它应该足以区分21秒和不到100毫秒。

所以我得出结论,你的基准测试有问题。

答案 3 :(得分:1)

我更新了您的示例以使用我在单元测试时使用的一些计时器代码。在我的机器上,我得到以下时间(基于-O3):

First loop 0.0040654
Second loop 4.8e-05
Intersection 0.000349
Intersection size: 50

基于此,如果我正确读取小数,则将项目插入第一组需要“4ms”,将项目插入第二组需要50微秒,执行1/3 ms十字路口。

我无法在我的机器上运行你的C#示例,所以我无法比较时间,但是你发布时绝对不是21秒。

答案 4 :(得分:0)

您的C#和C ++代码的工作方式不同。 C#代码使用神奇的散列技巧来提高速度,你的C ++代码使用树形技巧来提高速度。有一件事可能会加快速度(忽略你的测试似乎被打破的事实)将是使用散列,如下所示:

  1. 创建两个集合之一的hash_map
  2. 迭代第二个集合中的每个元素。如果`hash_map1包含该元素,请将其添加到结果中。