下午好,我们目前正在使用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)));
答案 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
};