简体   繁体   English

std :: vector &lt;std :: vector <unsigned char> &gt;或std :: deque &lt;std :: vector <unsigned char> &gt;?

[英]std::vector< std::vector<unsigned char> > or std::deque< std::vector<unsigned char> >?

I have an existing algorithm and I need to optimize it sligtly if it is possible. 我有一个现有的算法,如果可能的话,我需要适当地对其进行优化。 Changing a lot in this algorithm is not an option at the moment. 目前无法在此算法中进行大量更改。 The algoritm works with instance of std::vector< std::vector<unsigned char> > . 该算法适用于std::vector< std::vector<unsigned char> >实例。 It looks like this: 看起来像这样:

typedef std::vector<unsigned char> internal_vector_t;
std::vector< internal_vector_t > internal_vectors; 

while (fetching lots of records) {
   internal_vector_t tmp;
   // reads 1Mb of chars in tmp...
   internal_vectors.push_back(tmp);
   // some more work
}

// use this internal_vectors

The algorithm inserts a lot of times in internal_vectors instances of internal_vector_t using push_back(). 该算法使用push_back()在internal_vectors实例中插入了很多次。 Most of instances of internal_vector_t have size 1 Mb . internal_vector_t的大多数实例的大小为1 Mb Since the size of the internal_vectors is unknown no reserve() is done beforehand. 由于internal_vectors的大小是未知的,因此不会事先完成reserve()。

The first thing that I don't understand is what is happening when internal_vectors reachs its current capacity, needs to allocate a new block and copy its current content in the bigger block of memory. 我不明白的第一件事是当internal_vectors达到其当前容量时,需要分配一个新块并将其当前内容复制到更大的内存块中,这是怎么回事。 Since most of the blocks are 1Mb in size copying is a long operation. 由于大多数块的大小为1Mb,因此复制操作很长。 Should I expect that a compiler (gcc 4.3, MS VC++ 2008) will manage to optimize it in order to avoid copying ? 我是否应该期望编译器(gcc 4.3,MS VC ++ 2008)将设法对其进行优化以避免复制

If copying is unavoidable will changing to std::deque help ? 如果复制不可避免,将更改为std::deque help吗? I consider std::deque because I still need accessing by index like internal_vectors[10]. 我考虑使用std :: deque,因为我仍然需要按诸如internal_vectors [10]之类的索引进行访问。 Like this: 像这样:

typedef std::vector<unsigned char> internal_vector_t;
std::deque< internal_vector_t > internal_vectors; 
// the same while

As far as I understand std::deque does not need relocate that was once allocated. 据我了解std::deque不需要重新分配曾经分配的位置。 Am I right that std::deque in this situation will requere less allocation and copying on push_backs? 我在这种情况下的std::deque是否会要求较少的分配和在push_backs上复制的请求对吗?


Update: 更新:
1) According to DeadMG MSVC9 does this type of optimization (The Swaptimization - TR1 Fixes In VC9 SP1 ). 1)据DeadMG称, MSVC9进行了这种类型的优化(Swaptimization- TR1已在VC9 SP1中修复 )。 gcc 4.3 probably doesn't do this type of optimization. gcc 4.3可能不会进行这种优化。

2) I have profiled the version of the algorithm that use std::deque< std::vector<unsigned char> > and I see that its performace is better. 2)我已经介绍了使用std::deque< std::vector<unsigned char> >的算法版本,我发现它的性能更好。

3) I have also made use of using swap that was suggested by Mark Ransom . 3)我还利用了Mark Ransom建议的使用swap Using this improved the performance: 使用此功能可以改善性能:

  internal_vector_t tmp; internal_vectors.push_back(empty); tmp.swap(internal_vectors.back()); 

MSVC9 implements something known as "swaptimization" for it's Standard containers. MSVC9的标准容器实现了一种称为“ swaptimization”的功能。 It's a weaker version of move semantics. 它是移动语义的较弱版本。 When the external vector is resized, it will not copy the internal vectors. 调整外部向量的大小时,它将不会复制内部向量。

However, you'd do best simply upgrading your compiler to MSVC10 or GCC (4.5, I think it is) which will give you move semantics, which makes such operations vastly more efficient. 但是,您最好只是简单地将编译器升级到MSVC10或GCC(我认为是4.5),这将为您提供移动语义,这将大大提高此类操作的效率。 Of course, a std::deque is probably still the smarter container, but move semantics are performance-beneficial in many, many places. 当然, std::deque可能仍然是更聪明的容器,但是move语义在许多地方对性能都有好处。

Each time you insert a internal_vector_t into internal_vectors , it is going to make a copy of the internal_vector_t . 每次将internal_vector_t插入internal_vectors ,它都会复制一个internal_vector_t This will be true whether you use vector or deque . 无论您使用vector还是deque都是如此。 The standard containers always make a copy of the object you're inserting. 标准容器始终会复制您要插入的对象。

You can eliminate the copying by inserting an empty internal_vector_t and then swap the contents of the inserted object with the one you really wanted to insert. 您可以通过插入一个空的internal_vector_t消除复制,然后将插入的对象的内容与您真正想要插入的对象swap

Occasionally the vector will need to resize itself as it runs out of room during an insertion, which would result in objects being copied again. 有时,向量在插入过程中空间不足时需要调整自身大小,这将导致对象再次被复制。 A deque will eliminate this as long as you're always inserting at the beginning or end. 只要您始终插入开头或结尾,双端队列将消除这种情况。

Edit: The advice I gave above can be summarized with these code changes. 编辑:我上面给出的建议可以通过这些代码更改进行总结。 This code should avoid all copying of the large vectors. 此代码应避免所有复制大向量。

typedef std::vector<unsigned char> internal_vector_t;
std::deque< internal_vector_t > internal_vectors; 
internal_vector_t empty;

while (fetching lots of records) {
   internal_vector_t tmp;
   // reads 1Mb of chars in tmp...
   internal_vectors.push_back(empty);
   tmp.swap(internal_vectors.back());
   // some more work
}

std::deque does not store it's elements contiguously - it breaks it's storage up into a series of constant sized "blocks". std::deque不会连续存储其元素-它将其存储分解为一系列恒定大小的“块”。 This means that when a std::deque runs out of capacity it only needs to allocate a new block of constant size - it does not need to reallocate it's whole internal buffer and move all of it's existing elements. 这意味着,当std::deque容量不足时,它仅需要分配一个恒定大小的新块-无需重新分配其整个内部缓冲区并移动其所有现有元素。

std::vector on the other hand does maintain contiguous storage, so when it runs out of capacity and reallocates, it does need to move all of it's existing elements - this can be expensive. 另一方面, std::vector确实会保持连续存储,因此当容量用完并重新分配时,确实需要移动所有现有元素-这可能会很昂贵。

std::vector is "smart" about its reallocation scheme, allocating in chunks according to a geometric series (often doubling or increasing the capacity by 1.5 etc). std::vector关于它的重新分配方案是“智能的”,根据几何级数(通常是将容量增加一倍或增加1.5等)按块分配。 This means that reallocation doesn't occur often. 这意味着重新分配不会经常发生。

std::deque may be more efficient in this case since when reallocation does occur it does less work. 在这种情况下, std::deque可能会更有效,因为当重新分配确实发生时,它的工作量就会减少。 As always, you'd have to benchmark to get any real numbers. 与往常一样,您必须进行基准测试才能获得任何实数。

Your code could probably be improved further in other areas. 您的代码可能会在其他方面得到进一步改进。 It seems that at each iteration of the while loop you're creating a new internal_vector_t tmp . 似乎在while循环的每次迭代中,您都在创建一个新的internal_vector_t tmp It may be more efficient to declare this outside the loop and just ::clear() it's storage at each iteration. 在循环外声明它可能更有效,而::clear()其存储在每次迭代中。 You're also copying the whole tmp vector each time you call internal_vectors.push_back(tmp) - you could probably improve on this by just moving the tmp vector via internal_vectors.push_back(std::move(tmp)) - this will just copy a few pointers. 每次调用internal_vectors.push_back(tmp)时,您也要复制整个tmp矢量-您可以通过通过internal_vectors.push_back(std::move(tmp))移动tmp矢量来改善这一点。一些指针。

Hope this helps. 希望这可以帮助。

Are you indexing the outer vector? 您正在索引外部向量吗? If not, how about std::list<std::vector<unsigned char> > ? 如果不是,那么std::list<std::vector<unsigned char> >怎么样?

A dequeue may be more efficient depending on the implementation. 取决于实现,出队可能更有效。 Unlike a vector, a dequeue will not guarantee continuous storage and can thus allocate several separate blocks of memory. 与向量不同,出队将无法保证连续存储,因此可以分配几个单独的内存块。 Therefore it can allocate more memory without moving elements already added. 因此,它可以分配更多内存,而无需移动元素。 You should try it and measure the impact. 您应该尝试一下并评估影响。

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

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