【发布时间】:2012-02-23 14:49:13
【问题描述】:
我有一个过程,它用取自另一个数组的值填充一些数组。 它看起来类似于以下代码:
// Point 0
ptrlistVector.clear();
// Point 1
ptrlistVector.resize(50);
const size_t s = ptrlistVector.size();
// Point 2
for (ObjectList::iterator j = objList.begin(); j != objList.end(); ++j)
{
for (UINT i = 0; i < s; ++i)
{
ptrlistVector[i].push_back(&(*j));
}
}
// Point 3
实际上“push_back”行中有更复杂的代码——我将不同的值推送到一个列表中。这些值取决于某些条件。
声明和定义:
typedef std::list<void*> ObjectPtrList;
typedef std::vector<ObjectPtrList> PtrListVector;
typedef std::list<std::string> ObjectList;
ObjectList objList;
PtrListVector ptrlistVector;
我测量了点之间的时间,平均而言,点 1-0 需要 0.02 秒,点 3-2 需要 0.05 秒。 我试图重构循环并发现了一些奇怪的行为。 我用以下内容替换了上面的循环:
for (UINT i = 0; i < s; ++i)
{
for (ObjectList::iterator j = objList.begin(); j != objList.end(); ++j)
{
ptrlistVector[i].push_back(&(*j));
}
}
在那之后,时间发生了变化。第 3-2 点需要 0.035 秒,但 clear() 调用(第 1-0 点)现在需要 0.45(!!!),这比上一次要大得多。
我使用 MSVC 10.0,Debug 和 Release 模式下的结果大致相同。在Release模式下,时间差不是那么大,但无论如何,第二个的时间会更大。
谁能解释一下为什么在我更改循环后 clear() 调用需要更多时间?
下面的代码是我用于性能测试的控制台应用程序。
#include "stdafx.h"
#include <windows.h>
#include <vector>
#include <list>
#include <cstdio>
#include <cassert>
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
typedef std::list<void*> ObjectPtrList;
typedef std::vector<ObjectPtrList> PtrListVector;
typedef std::list<std::string> ObjectList;
ObjectList objList;
objList.insert(objList.begin(), 500, std::string());
PtrListVector ptrlistVector;
LARGE_INTEGER __counters[10];
double __totals[10] = { 0 };
UINT __counter = 0;
BOOL bRes;
LARGE_INTEGER __freq;
bRes = QueryPerformanceFrequency(&__freq);
assert(bRes);
for (int k = 0; k < 500; ++k)
{
// Point 0
bRes = QueryPerformanceCounter(&__counters[0]);
ptrlistVector.clear();
// Point 1
bRes = QueryPerformanceCounter(&__counters[1]);
ptrlistVector.resize(50);
const size_t s = ptrlistVector.size();
// Point 2
bRes = QueryPerformanceCounter(&__counters[2]);
/*
// original
for (ObjectList::iterator j = objList.begin(); j != objList.end(); ++j)
{
for (UINT i = 0; i < s; ++i)
{
ptrlistVector[i].push_back(&(*j));
}
}
/*/
for (UINT i = 0; i < s; ++i) // refactored
{
for (ObjectList::iterator j = objList.begin(); j != objList.end(); ++j)
{
ptrlistVector[i].push_back(&(*j));
}
}
//*/
// Point 3
bRes = QueryPerformanceCounter(&__counters[3]);
__counter += 1;
__totals[1] += 1.0 * (__counters[1].QuadPart - __counters[0].QuadPart) / __freq.QuadPart;
__totals[2] += 1.0 * (__counters[2].QuadPart - __counters[1].QuadPart) / __freq.QuadPart;
__totals[3] += 1.0 * (__counters[3].QuadPart - __counters[2].QuadPart) / __freq.QuadPart;
__totals[4] += 1.0 * (__counters[3].QuadPart - __counters[0].QuadPart) / __freq.QuadPart;
printf("%s: %.4f %.4f %.4f = %.4f\n",
__FUNCTION__,
__totals[1]/__counter,
__totals[2]/__counter,
__totals[3]/__counter,
__totals[4]/__counter);
}
return 0;
}
【问题讨论】:
-
调用
reserve,并在循环之前将元素数量添加到vector,clear应该会更快。 -
你确定
ptrlistVector.resize(50)?它向您的向量添加了 50 个默认构造的对象(在您的情况下只是空指针),然后您添加了更多项目。有点可疑。 -
安迪,是的,我确定。我不测量调整大小的调用。而且我不再将项目添加到向量中,而是将项目添加到作为向量元素的空列表中。
-
抱歉,没抓住重点。我检查了两个版本并收到几乎相同的结果:原始版本为“total 0.0022”,重构版本为“total 0.0023”
标签: c++ visual-c++ optimization loops stl