是否可以将STL设置为比STL multiset更快以防止重复条目?

时间:2011-06-27 17:33:03

标签: c++ visual-studio stl

下午好,我们目前正在使用STL multimap和STL设置来缓存内存映射文件区域。我们希望我们的缓存只有唯一的条目。我们想知道是否存在STL集和STL映射比STL multiset和STL multimap更快以防止重复条目的方法。       我们使用以下代码摘录来防止STL multimap和STL设置重复条目。是否有可能加快速度?谢谢。

int distance(char* x, char* y,int error){ 
    if (x >= y && (x - y) <= error){ 
        return 0;
    }
    return (x - y);
};

class MinDist {
public:
    MinDist(){}

    MinDist(char* & p, const int & error){}

    bool operator() (char *  p1, char *  p2 )
    {
      return distance( p1, myPoint, myError) < distance( p2,  myPoint, myError); 
    }

public:
    static char* myPoint;
    static int myError;
};


std::multiset<Range> ranges_type; 
std::multimap<char *,Range, MinDist> mmultimap;


MinDist::myPoint = TmpPrevMapPtr;
MinDist::myError = MEM_BLOCK_SIZE;

std::pair<I,I> b = mmultimap.equal_range(TmpPrevMapPtr); 
for (I i=b.first; i != b.second; ++i){ 
     ranges_type.erase(i->second);
     numerased++;
}

typedef std::multimap<char*,Range,MinDist>::iterator J;
std::pair<J,J> pr = mmultimap.equal_range(TmpPrevMapPtr); 


erasecount = 0;
J iter = pr.first;
J enditer = pr.second;
for(  ; iter != enditer ; ){ 
    if ((*iter).first == TmpPrevMapPtr){
        mmultimap.erase(iter++); 
        erasecount++;
    }
    else{
        ++iter;
    }
}

MinDist::myPoint = 0; 

ranges_type.insert(RangeMultiSet::value_type(n, n + mappedlength,
                &adjustedptr[n],MapPtr,mappedlength));


mmultimap.insert(RangeMultiMap::value_type(MapPtr,
                   Range(n,n + mappedlength,
                      &adjustedptr[n],
                      MapPtr,mappedlength)));

3 个答案:

答案 0 :(得分:2)

这里有很多东西需要阅读,复杂容器类型的优化是一个棘手的问题。我花了相当多的时间研究类似的问题,所以我会试着指出一些对我有帮助的事情。

首先,使代码更快的通常方法是当向量执行时不使用二叉树。对于你的map / set中的每个节点,Microsoft STL实现将花费大约14个字节(3个指针+最后我检查的红色/黑色标志的短int)开销,以及在它到来之前至少4个字节的malloc开销存储节点数据。虽然我不太了解您的域的具体细节,但内存映射I / O让我觉得可能存在复杂但更快的基于矢量的解决方案。这将要求您同时映射的块数量很小 - 如果您的查找表达到或小于6,000字节,带有memmove用于插入/擦除的排序数组实现,以及用于查找的binary_search可能会更快发布模式(在调试模式下,它可能会快几个兆字节,遗憾的是)。如果元素是4字节指针,则6,000字节允许最多1,500个映射块。

然而,有时你只需要使用树木。一种情况是复杂节点(因此构造/破坏是必要的)或相当高的元素数(因此O(N)数组插入变得比O(log n)树插入的malloc成本慢)。你能在这做什么?注意map / multimap和set / multiset或几乎相同的速度;多*版本确实有点慢,但只是因为处理它们的代码要长几行。

无论如何,有一件事可以帮助很多,就是弄清楚如何削减malloc成本,因为每个节点都会在某个时刻调用malloc / free。切割困难 - 释放模式分配器大约相当于大约50-200个算术运算,因此虽然它可以打败,但需要花费一些精力。你确实有一些希望 - 映射/设置分配的大小都相同,因此内存池可以很好地工作。 Google可能是开始的好方法;关于这个话题有很多好文章。

最后,有一个我发现非常有用的开源采样分析器 - 它被称为Very Sleepy,通常在Visual Studio项目上运行。如果你想在你的情况下明确回答map / multimap或set / multiset是否更快,那就是我要指出的主要内容。祝你好运!

答案 1 :(得分:1)

以下是一般情况:

#include <cstddef>   // for size_t
#include <set>       // for std::set
#include <algorithm> // for std::swap
#include <ostream>   // for std::ostream

struct Range
{
  int start, end; // interpret as [start, end), so Range(n,n) is empty!

  Range(int s, int e) : start(s), end(e)
  {
    if (start > end) std::swap(start, end);
  }

  inline bool operator<(const Range & r) const
  {
    return (start < r.start) || (!(r.start > start) && end < r.end);
  }

  inline size_t size() const { return end - start; }
};

std::ostream & operator<<(std::ostream & o, const Range & r)
{
  return o << "[" << r.start << ", " << r.end << ")";
}

typedef std::set<Range> cache_t;

cache_t::const_iterator findRange(int pos, const cache_t & cache)
{
  cache_t::const_iterator it = cache.lower_bound(Range(pos, pos)),
                         end = cache.end();

  for ( ; it != end && it->start <= pos ; ++it) // 1
  {
    if (it->end > pos) return it;
  }

  return end;
}

inline bool inRange(int pos, const cache_t & cache)
{
  return findRange(pos, cache) != cache.end();
}

现在,您可以使用findRange(pos, cache)来发现某个位置是否已被缓存中的某个范围覆盖。

请注意,// 1处的循环非常有效,因为它仅从pos可能出现的第一个元素开始,一旦pos无法再在范围内就停止。对于非重叠范围,这将涵盖至多一个范围!

答案 2 :(得分:0)

class Range { 
    public:   
        explicit Range(int item = 0)
        : mLow(item), mHigh(item), mPtr(0), mMapPtr(0) { }

        Range(int low, int high, char* ptr = 0, char * mapptr = 0, int currMappedLength = 0)
        : mLow(low), mHigh(high), mPtr(ptr), mMapPtr(mapptr), mMappedLength(currMappedLength) { }

        Range(const Range& r)
        : mLow(r.mLow), mHigh(r.mHigh), mMapPtr(r.mMapPtr), mMappedLength(r.mMappedLength) { }

        bool operator<(const Range& rhs) const { return mHigh < rhs.mHigh; }

        int   low()       const { return mLow; }   
        int   high()      const { return mHigh; }
        char* getMapPtr() const { return mMapPtr; }
        int getMappedLength() const { return mMappedLength; }

     private:   
         int mLow;          // beginning of memory mapped file region
         int mHigh;         // end of memory mapped file region 
         char* mMapPtr;     // return value from MapViewOfFile
         int mMappedLength; // length of memory mapped region
};