为什么STL中的set_intersection这么慢?

发布于 2024-07-25 07:16:59 字数 2038 浏览 3 评论 0原文

我在 STL 中使用 set_intersection 对一组 100,000 个数字和一组 1,000 个数字进行相交,需要 21 秒,而在 C# 中需要 11 毫秒。

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;
    }
}

I'm intersecting a set of 100,000 numbers and a set of 1,000 numbers using set_intersection in STL and its taking 21s, where it takes 11ms in C#.

C++ Code:

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# Code:

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;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

愁以何悠 2024-08-01 07:16:59

有几件事会让你的两个例子更具可比性。

首先,你在STL中的例子不太正确,一方面,两个集合都应该按升序排序(在STL中讲“严格弱排序”)。

其次,您使用的“集合”在 STL 中以树的形式实现,而“列表”则是链接列表。 随机插入到集合中比插入到列表末尾更昂贵。

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

A couple things would make your two examples more comparable.

First, your example in STL isn't quite right, for one thing both sets should be sorted in ascending order (in STL speak a "strict weak ordering").

Second, your using "sets" which are implemented as trees in STL, vs. "lists" which are linked lists. Random inserts into a set is more expensive than inserting onto the end of a list.

Try using a list of ints in the C++ example and also sort the list first (otherwise set inersection won't work properly) and I think you'll see more favorable results.

面犯桃花 2024-08-01 07:16:59

我在我的 linux box 21s 上运行了你的 C++ 代码,

$ time ./test

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

对我来说意味着你在没有优化的情况下编译了。 如果您使用 MSVC,请确保您已列出
_SECURE_SCL=0(请参阅 msdn )在编译定义中。 否则,所有 STL 迭代器操作都非常慢。

I ran your C++ code on my linux box

$ time ./test

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

21s means to me you compiled without optimizations. In case you use MSVC make sure you have listed
_SECURE_SCL=0 (see msdn) in the compile definitions. Otherwise all STL iterator operations are dog slow.

于我来说 2024-08-01 07:16:59

在这个古老的 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 毫秒。

所以我的结论是你的基准有问题。

On this ancient 3GHz Pentium 4, I get 2734 milliseconds for the entire runIntersectionTestAlgo function, in a debug build with optimizations disabled. I compiled with VS2008 SP1.

If I enable optimizations, I get 93 milliseconds.

Here's my code:

#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";
}

Disabling _SECURE_SCL made no difference for the release build, which still hovered around the 100 ms.

GetTickCount isn't ideal, of course, but it should be good enough to distinguish 21 seconds from less than 100 milliseconds.

So I conclude that there's something wrong with your benchmarks.

安人多梦 2024-08-01 07:16:59

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

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

基于此,如果我正确读取小数,则需要“4 毫秒”才能将项目插入到第一组中,需要 50 微秒才能将项目插入到第二组和 1/3 毫秒来执行相交。

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

I updated your example to use some timer code that I use when unit testing. On my machine I get the following timings (based on -O3):

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

Based on that, if I'm reading my decimals correctly, it takes '4ms' to insert the items into the first set, 50 microseconds to insert the items into the second set and a 1/3 of a ms to perform the intersection.

I am unable to run your C# example on my machine, so I cannot compare the timing, but it's definitely not 21s as you post.

赏烟花じ飞满天 2024-08-01 07:16:59

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

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

Your C# and C++ code work differently. The C# code uses magical hashing tricks for speed, your C++ code uses tree tricks for speed. One thing that will probably speed things up (ignoring the fact that your testing seems to be broken) would be to using hashing, as follows:

  1. Create a hash_map of one of the two collections.
  2. Iterate over each element in the 2nd collection. If the `hash_map1 contains that element, add it to your result.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文