【问题标题】:Is the efficiency of std::map::find related to the data size of the value?std::map::find 的效率与值的数据大小有关吗?
【发布时间】:2017-08-07 11:42:25
【问题描述】:

我使用std::map<std::pair<int, int>, class B> 来保存网格图的信息,B 类包含大约 10000 字节的数据。我发现40000次find操作大约需要10ms,虽然map只有四个key-value。当我将 B 类的数据大小减小到 2500 Bytes 时,成本也降低到了 3.5ms 左右。我知道find操作的时间复杂度是O(log(N)),这是什么原因造成的?

【问题讨论】:

  • 您有一个发现并使用了比较 - 无序地图会更快吗?
  • 您必须准备并显示MCVE 才能获得好的答案。否则我们只是猜测。
  • @Useless MCVE 非常荣幸,但这为此事提供了相当多的背景信息。这是一个相当笼统的问题,我怀疑通过显示三行代码来改进它......完全按照他的描述进行。
  • 我用gettimeofday函数计算了40000次find操作的时间成本,发现当B类的数据量不同时,时间成本是不同的
  • Big O 表示法!= 运行时性能。但在这种情况下,问题可能出在数据局部性上。如果值很大,则执行比较的键之间可能有相当大的距离。您可以尝试用指向值的指针或存储在其他地方的值的索引替换值项并检查结果。

标签: c++ performance dictionary stl


【解决方案1】:

我很好奇并尝试了一个简单的测试。测试代码如下(用VS2015编译)。

这是我在发布版本中运行代码时得到的结果(优化):

Value10k: 0.126498 ms
Value2k: 0.121991 ms

这是调试版本中的输出:

Value10k: 120.187 ms
Value2k: 95.5364 ms

在发布版本中,差异可以忽略不计;在调试版本中似乎存在一些差异(尽管对于性能数据,我更倾向于发布版本)。

我不知道map::find方法的实现细节。无论如何,请注意大 O 符号只是故事的一部分。另一个需要考虑的重要性能方面是数据的缓存友好性、数据局部性等。

我什至不知道您的 B 类是否正在进行一些昂贵的复制操作。

无论如何,我建议测量您的代码性能,并与其他变体进行比较,例如使用unique_ptr<B>shared_ptr<B> 作为地图的值。


可编译的测试代码如下:

#include <iostream>
#include <map>
#include <windows.h>
using namespace std;

template <int DimT>
struct Value
{
    char Data[DimT];
};

typedef Value<10000> Value10k;
typedef Value<2000> Value2k;


long long Counter() 
{
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return li.QuadPart;
}

long long Frequency() 
{
    LARGE_INTEGER li;
    QueryPerformanceFrequency(&li);
    return li.QuadPart;
}

void PrintTime(const long long start, const long long finish, const char * const msg)
{
    cout << msg << ": " << (finish - start) * 1000.0 / Frequency() << " ms\n";
}

bool IsEven(int n)
{
    return (n % 2) == 0;
}

int main() 
{
    map<pair<int, int>, Value10k> m1;
    m1[make_pair(0, 0)] = Value10k{};
    m1[make_pair(0, 1)] = Value10k{};
    m1[make_pair(1, 0)] = Value10k{};
    m1[make_pair(1, 1)] = Value10k{};

    constexpr int searchCount = 40000;

    auto start = Counter();
    for (int i = 0; i < searchCount; i++)
    {
        int x{};
        int y{};
        if (IsEven(i))
        {
            x = 0;
            y = 1;
        }
        else
        {
            x = 1;
            y = 0;
        }
        auto search = m1.find(make_pair(x, y));
    }
    auto finish = Counter();
    PrintTime(start, finish, "Value10k");


    map<pair<int, int>, Value2k> m2;
    m2[make_pair(0, 0)] = Value2k{};
    m2[make_pair(0, 1)] = Value2k{};
    m2[make_pair(1, 0)] = Value2k{};
    m2[make_pair(1, 1)] = Value2k{};

    start = Counter();
    for (int i = 0; i < searchCount; i++)
    {
        int x{};
        int y{};
        if (IsEven(i))
        {
            x = 0;
            y = 1;
        }
        else
        {
            x = 1;
            y = 0;
        }
        auto search = m2.find(make_pair(x, y));
    }
    finish = Counter();
    PrintTime(start, finish, "Value2k");
}

【讨论】:

    猜你喜欢
    • 2011-02-10
    • 1970-01-01
    • 2017-07-18
    • 2021-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-02
    相关资源
    最近更新 更多