简体   繁体   English

使用带预分配 std::unordered_map 的嵌套向量快速构造 unordered_map <int, vector<thing *> >?</int,>

[英]Fast construction of unordered_map with nested vector with preallocation std::unordered_map<int, vector<Thing *>>?

I want to create map of int to vector of Things*.我想创建 map 的 int 到 Things* 的向量。 I know that Thing will be 1-50 no more.我知道Thing将不再是 1-50。 How can I allocate 50 at start to speed up construction of map?如何在开始时分配 50 以加快 map 的构建?

I tried three methods but still not sure if it enough fast.我尝试了三种方法,但仍然不确定它是否足够快。 Can you suggest better optimization?你能建议更好的优化吗? I was using c++ 10 years ago and I am not sure if I do it correctly.我在 10 年前使用 c++,我不确定我是否正确使用。 Can you help?你能帮我吗? All optimization suggestions are welcome.欢迎所有优化建议。 Code is simplified from real problem.代码是从实际问题中简化而来的。

#include <iostream>
#include <vector>
#include <unordered_map>

#include <time.h>

class Thing {
};

int main()
{
    clock_t start;
    start = clock();
    auto int_to_thing = std::unordered_map<int, std::vector<Thing *>>();
    for (int i = 0; i < 1000; i++) {
        for (int j = 0; j < 25; j++) {
            int_to_thing[i].push_back(new Thing());
        }
    }
    for (int i = 0; i < 1000; i++) {
        for (int j = 0; j < 25; j++) {
            int_to_thing[i].push_back(new Thing());
        }
    }
    std::cout << (clock() - start) << std::endl;

    start = clock();
    int_to_thing = std::unordered_map<int, std::vector<Thing *>>();
    for (int i = 0; i < 1000; i++) {
        int_to_thing[i].reserve(50);
        for (int j = 0; j < 25; j++) {
            int_to_thing[i].push_back(new Thing());
        }
    }
    for (int i = 0; i < 1000; i++) {
        for (int j = 0; j < 25; j++) {
            int_to_thing[i].push_back(new Thing());
        }
    }
    std::cout << (clock() - start) << std::endl;

    start = clock();
    int_to_thing = std::unordered_map<int, std::vector<Thing *>>();
    for (int i = 0; i < 1000; i++) {
        auto it = int_to_thing.find(i);
        if (it != int_to_thing.end()) {
            auto v = std::vector<Thing *>(50);
            auto pair = std::pair<int, std::vector<Thing *>>(i, v);
            int_to_thing.insert(pair);
        }
    }
    for (int i = 0; i < 1000; i++) {
        for (int j = 0; j < 25; j++) {
            int_to_thing[i].push_back(new Thing());
        }
    }
    std::cout << (clock() - start) << std::endl;
    
    return 0;
}

Are you concerned about the construction of the map (then see @ShadowRanger's comment) or the construction of the vectors?您是否关心map的构造(然后查看@ShadowRanger 的评论)或向量的构造?

I assume that there are 1..50 Thing 's in a vector, NOT 1..50 vectors in a map.我假设一个向量中有 1..50 个Thing ,而不是 map 中的 1..50 个向量。

Your code:你的代码:

int_to_thing = std::unordered_map<int, std::vector<Thing *>>();
for (int i = 0; i < 1000; i++) {
    int_to_thing[i].reserve(50);

is the best option.是最好的选择。 It constructs a map of vectors and, inside the loop, creates each vector and pre-allocates room for 50 elements.它构造一个 map 向量,并在循环内创建每个向量并为 50 个元素预分配空间。

Without that reserve() you would likely encounter a couple of reallocation while pushing 50 elements into those vectors.如果没有reserve() ,您可能会在将 50 个元素推入这些向量时遇到几次重新分配。

Using:使用:

auto v = std::vector<Thing *>(50);

actually creates 50 elements in your vector,and default-initializes them.实际上在你的向量中创建了50 个元素,并默认初始化它们。 This may or may not cost you extra.这可能会或可能不会花费您额外的费用。 Specifically, it will be cheap with your current use of pointers, and expensive if you switch to storing the Thing objects themselves.具体来说,对于您当前使用的指针,它会很便宜,而如果您转而存储Thing对象本身,则会很昂贵。

If you are unsure that something is fast enough then you are not measuring performance and this is prima facie evidence that you don't care one iota about it.如果您不确定某件事是否足够快,那么您就没有在衡量性能,这是初步证据表明您根本不在乎它。 If you don't measure it then you cannot claim anything about it.如果你不测量它,那么你就不能对它提出任何要求。 Measure it first before you do anything else.在你做任何其他事情之前先测量它。 Otherwise you'll waste everyone's time.否则你会浪费大家的时间。 You work on an assumption that such preallocations will help.您假设此类预分配会有所帮助。 I have an inkling that they won't help at all since you make so few of them, and you're just wasting your time.我有一种暗示,他们根本帮不上忙,因为你做的太少了,你只是在浪费时间。 Again: if you are serious about performance, you stop now, get measurements in place, and come back with some numbers to talk over.再说一次:如果你对性能很认真,你现在就停下来,进行适当的测量,然后带着一些数字回来讨论。 And don't measure debug builds - only release builds with full optimization turned on, including link time code generation (LTCG).并且不要测量调试构建——只测量启用了全面优化的发布构建,包括链接时间代码生成 (LTCG)。 If you don't optimize, you don't care about performance either.如果你不优化,你也不关心性能。 Period.时期。 Full stop.句号。 Those are the rules.这些是规则。

Yes, you have code that times stuff but that's not what measurements are about.是的,你有代码来计算时间,但这不是测量的目的。 They need to happen in the context of your use of the data, so that you can see what relative overhead you have.它们需要在您使用数据的上下文中发生,以便您可以看到您有多少相对开销。 If the task takes an hour and you spend a second doing this “unoptimally”, then there's no point in optimizing that first - you got bigger fish to fry first.如果这项任务需要一个小时,而你花了一秒钟来做这个“非最佳”,那么首先优化它是没有意义的——你有更大的鱼要先煎。 And besides, in most context the code is cache-driven ie data access patterns determine performance so I don't believe you're doing anything useful at all at the moment.此外,在大多数情况下,代码是缓存驱动的,即数据访问模式决定性能,所以我认为您目前根本没有做任何有用的事情。 Such micro optimizations are totally pointless.这样的微优化完全没有意义。 This code doesn't exist in a vacuum.此代码不存在于真空中。 If it did, you can just remove it and forget about it all, right?如果是这样,您可以将其删除并忘记这一切,对吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM