上篇文章中发现内存生生循环居然比使用空间索引速度还快,昨儿睡前想到之前与同事讨论过且网上查过的一个问题:继承类函数虚表调用导致的效率下降,于是今儿写了点测试代码,以Envelope的Intersect方法作为测试内容,对比了结构体、类、虚基类、派生类的函数调用效率
#include "stdafx.h"
#include "CompIndex_Spatial.h"
#include
using namespace std;
#include "shapefil.h"
class CEnvelope;
class IEnvelope;
class Envelope;
struct stEnvelope
{
stEnvelope(size_t i, double x1, double x2, double y1, double y2)
{
id = i;
x_min = x1;
x_max = x2;
y_min = y1;
y_max = y2;
}
bool intersect(stEnvelope *pOther)
{
return x_min <= pOther->x_max &&
x_max >= pOther->x_min &&
y_min <= pOther->y_max &&
y_max >= pOther->y_min;
}
size_t id;
double x_min;
double x_max;
double y_min;
double y_max;
};
typedef list OriginEnvelopes;
class CEnvelope
{
public:
CEnvelope(size_t i, double x1, double x2, double y1, double y2)
{
id = i;
x_min = x1;
x_max = x2;
y_min = y1;
y_max = y2;
}
~CEnvelope(){}
public:
bool intersect(CEnvelope *pOther)
{
return x_min <= pOther->x_max &&
x_max >= pOther->x_min &&
y_min <= pOther->y_max &&
y_max >= pOther->y_min;
}
private:
size_t id;
double x_min;
double x_max;
double y_min;
double y_max;
};
class IEnvelope
{
public:
virtual bool intersect(IEnvelope *pOther) = 0;
};
class Envelope : public IEnvelope
{
public:
Envelope(size_t i, double x1, double x2, double y1, double y2)
{
id = i;
x_min = x1;
x_max = x2;
y_min = y1;
y_max = y2;
}
public:
virtual bool intersect(IEnvelope *pOther)
{
Envelope *pEnvlp = dynamic_cast(pOther);
if (!pEnvlp)
return false;
return x_min <= pEnvlp->x_max &&
x_max >= pEnvlp->x_min &&
y_min <= pEnvlp->y_max &&
y_max >= pEnvlp->y_min;
}
private:
size_t id;
double x_min;
double x_max;
double y_min;
double y_max;
};
static IEnvelope * CreateEnvelope(size_t i, double x1, double x2, double y1, double y2)
{
Envelope *pEnvelope = new Envelope(i,x1,x2,y1,y2);
return pEnvelope;
}
static void DestroyEnvelope(IEnvelope *pEnvelope)
{
if (pEnvelope)
{
delete pEnvelope;
pEnvelope = NULL;
}
}
bool init_data(OriginEnvelopes &envlps);
void free_data(OriginEnvelopes &envlps);
void Loop1(const OriginEnvelopes &envlps); // list<结构体>存储,直接取成员
void Loop2(const OriginEnvelopes &envlps); // list<类>存储,函数调用
void Loop3(const OriginEnvelopes &envlps); // list<派生类>存储,虚函数调用
void Loop4(const OriginEnvelopes &envlps); // list<虚接口>存储,虚基类调用
bool init_data(OriginEnvelopes &envlps)
{
string strShpPath = g_strDataDir + g_strDataset + ".shp";
SHPHandle hSHP = SHPOpen(strShpPath.c_str(), "rb");
if (NULL == hSHP)
return false;
SHPSetFastModeReadObject(hSHP, true);
int nEntities(0),nShapeType(0);
double padfMinBound[4],padfMaxBound[4];
SHPGetInfo(hSHP, &nEntities, &nShapeType, padfMinBound, padfMaxBound);
for (int i=0; idfXMin,pObj->dfXMax, pObj->dfYMin,pObj->dfYMax);
envlps.push_back(pEnvlp);
SHPDestroyObject(pObj);
}
SHPClose(hSHP);
return true;
}
void free_data(OriginEnvelopes &envlps)
{
for (OriginEnvelopes::iterator iter=envlps.begin(); iter!=envlps.end(); ++iter)
{
delete (*iter);
(*iter) = NULL;
}
envlps.clear();
}
const int c_iQueryTimes = 100;
// list<结构体>存储,无函数调用
void Loop1(const OriginEnvelopes &envlps)
{
clock_t tBeg,tEnd;
int iQueryCnt(0);
string strCurr("Loop1");
typedef OriginEnvelopes Envelopes;
Envelopes envelopes;
// 1.insert
tBeg = clock();
for (OriginEnvelopes::const_iterator iter=envlps.begin(); iter!=envlps.end(); ++iter)
{
stEnvelope *pEnvlp = new stEnvelope((*iter)->id, (*iter)->x_min, (*iter)->x_max, (*iter)->y_min, (*iter)->y_max);
envelopes.push_back(pEnvlp);
}
tEnd = clock();
printf("%s:insert:%d\n", strCurr.c_str(), tEnd-tBeg);
// 2.query
tBeg = clock();
stEnvelope qEnvelope(-1, g_x_min,g_x_max, g_y_min,g_y_max);
for (int iVal=0; iValintersect(&qEnvelope))
{
++iQueryCnt;
}
}
}
tEnd = clock();
printf("%s:query:%d\n", strCurr.c_str(), tEnd-tBeg);
// 3.clean
tBeg = clock();
for (Envelopes::iterator iter=envelopes.begin(); iter!=envelopes.end(); ++iter)
{
delete (*iter);
(*iter) = NULL;
}
envelopes.clear();
tEnd = clock();
printf("%s:clean:%d\n", strCurr.c_str(), tEnd-tBeg);
}
// list<类>存储,函数调用
void Loop2(const OriginEnvelopes &envlps)
{
clock_t tBeg,tEnd;
int iQueryCnt(0);
string strCurr("Loop2");
typedef list Envelopes;
Envelopes envelopes;
// 1.insert
tBeg = clock();
for (OriginEnvelopes::const_iterator iter=envlps.begin(); iter!=envlps.end(); ++iter)
{
CEnvelope *pEnvlp = new CEnvelope((*iter)->id, (*iter)->x_min, (*iter)->x_max, (*iter)->y_min, (*iter)->y_max);
envelopes.push_back(pEnvlp);
}
tEnd = clock();
printf("%s:insert:%d\n", strCurr.c_str(), tEnd-tBeg);
// 2.query
CEnvelope qEnvelope(-1, g_x_min,g_x_max, g_y_min,g_y_max);
tBeg = clock();
for (int iVal=0; iValintersect(&qEnvelope))
{
++iQueryCnt;
}
}
}
tEnd = clock();
printf("%s:query:%d\n", strCurr.c_str(), tEnd-tBeg);
// 3.clean
tBeg = clock();
for (Envelopes::iterator iter=envelopes.begin(); iter!=envelopes.end(); ++iter)
{
delete (*iter);
(*iter) = NULL;
}
envelopes.clear();
tEnd = clock();
printf("%s:clean:%d\n", strCurr.c_str(), tEnd-tBeg);
}
// list<派生类>存储,虚函数调用
void Loop3(const OriginEnvelopes &envlps)
{
clock_t tBeg,tEnd;
int iQueryCnt(0);
string strCurr("Loop3");
typedef list Envelopes;
Envelopes envelopes;
// 1.insert
tBeg = clock();
for (OriginEnvelopes::const_iterator iter=envlps.begin(); iter!=envlps.end(); ++iter)
{
Envelope *pEnvlp = new Envelope((*iter)->id, (*iter)->x_min, (*iter)->x_max, (*iter)->y_min, (*iter)->y_max);
envelopes.push_back(pEnvlp);
}
tEnd = clock();
printf("%s:insert:%d\n", strCurr.c_str(), tEnd-tBeg);
// 2.query
Envelope qEnvelope(-1, g_x_min,g_x_max, g_y_min,g_y_max);
tBeg = clock();
for (int iVal=0; iValintersect(&qEnvelope))
{
++iQueryCnt;
}
}
}
tEnd = clock();
printf("%s:query:%d\n", strCurr.c_str(), tEnd-tBeg);
// 3.clean
tBeg = clock();
for (Envelopes::iterator iter=envelopes.begin(); iter!=envelopes.end(); ++iter)
{
delete (*iter);
(*iter) = NULL;
}
envelopes.clear();
tEnd = clock();
printf("%s:clean:%d\n", strCurr.c_str(), tEnd-tBeg);
}
// list<虚基类>存储,虚函数调用
void Loop4(const OriginEnvelopes &envlps)
{
clock_t tBeg,tEnd;
int iQueryCnt(0);
string strCurr("Loop4");
typedef list Envelopes;
Envelopes envelopes;
// 1.insert
tBeg = clock();
for (OriginEnvelopes::const_iterator iter=envlps.begin(); iter!=envlps.end(); ++iter)
{
IEnvelope *pEnvlp = CreateEnvelope((*iter)->id, (*iter)->x_min, (*iter)->x_max, (*iter)->y_min, (*iter)->y_max);
envelopes.push_back(pEnvlp);
}
tEnd = clock();
printf("%s:insert:%d\n", strCurr.c_str(), tEnd-tBeg);
// 2.query
Envelope qEnvelope(-1, g_x_min,g_x_max, g_y_min,g_y_max);
tBeg = clock();
for (int iVal=0; iValintersect(&qEnvelope))
{
++iQueryCnt;
}
}
}
tEnd = clock();
printf("%s:query:%d\n", strCurr.c_str(), tEnd-tBeg);
// 3.clean
tBeg = clock();
for (Envelopes::iterator iter=envelopes.begin(); iter!=envelopes.end(); ++iter)
{
DestroyEnvelope(*iter);
(*iter) = NULL;
}
envelopes.clear();
tEnd = clock();
printf("%s:clean:%d\n", strCurr.c_str(), tEnd-tBeg);
}
void TestLoopEfficiency()
{
OriginEnvelopes envlps;
init_data(envlps);
Loop1(envlps);
Loop2(envlps);
Loop3(envlps);
Loop4(envlps);
free_data(envlps);
printf("\n");
}
insert | query | clean | info | |
---|---|---|---|---|
Loop1 | 197 | 904 | 123 | list<结构体>存储,函数调用 |
Loop2 | 188 | 897 | 126 | list<类>存储,函数调用 |
Loop3 | 185 | 4540 | 132 | list<派生类>存储,虚函数调用 |
Loop4 | 186 | 4564 | 132 | list<虚基类>存储,虚函数调用 |
http://blog.csdn.net/hengyunabc/article/details/7461919
回到开篇的问题,由于上篇文章中使用的是结构体计算intersect(小插曲:上篇使用的是结构体直接取成员变量,效率比本篇中调用结构体成员函数要低一些),与各索引算法中使用了较为复杂的类结构及派生关系比不能相提并论,如果将两次的表合起来对比,大约是内存索引所有节点为4.5s左右,使用rtree索引速度为3s左右(各个库的索引算法中的函数调用次数也不仅仅是本例中写的单一intersect函数),还是存在一定效率优势的