为了回答这个问题:
我的问题是,由于在这种情况下不会一次线性地迭代一个连续的数组,我是否立即牺牲了通过这种方式分配组件的性能收益?当我在C ++中迭代两个不同的连续数组并在每个循环中使用两个数组中的数据时,这是否会产生问题?
不(至少不一定)。在大多数情况下,高速缓存控制器应能够有效地处理从多个连续数组中读取数据的问题。重要的部分是尝试尽可能线性地访问每个数组。
为了证明这一点,我编写了一个小基准(适用常规基准警告)。
从简单的向量结构开始:
struct float3 { float x, y, z; };
我发现一个循环,将两个单独的数组的每个元素求和,并将结果存储在第三个数组中,与将源数据插入单个数组中并在第三个数组中存储结果的版本完全相同。但是,我确实发现,如果将结果与源进行交错处理,则性能会受到影响(大约2倍)。
如果我随机访问数据,性能将受到10到20的影响。
时间(10,000,000个元素)
线性访问
- 单独的数组0.21s
- 交错源0.21s
- 交错的源和结果0.48s
随机访问(取消注释random_shuffle)
- 分离数组2.42s
- 交错源4.43s
- 交错的源和结果4.00s
来源(与Visual Studio 2013编译):
#include <Windows.h>
#include <vector>
#include <algorithm>
#include <iostream>
struct float3 { float x, y, z; };
float3 operator+( float3 const &a, float3 const &b )
{
return float3{ a.x + b.x, a.y + b.y, a.z + b.z };
}
struct Both { float3 a, b; };
struct All { float3 a, b, res; };
// A version without any indirection
void sum( float3 *a, float3 *b, float3 *res, int n )
{
for( int i = 0; i < n; ++i )
*res++ = *a++ + *b++;
}
void sum( float3 *a, float3 *b, float3 *res, int *index, int n )
{
for( int i = 0; i < n; ++i, ++index )
res[*index] = a[*index] + b[*index];
}
void sum( Both *both, float3 *res, int *index, int n )
{
for( int i = 0; i < n; ++i, ++index )
res[*index] = both[*index].a + both[*index].b;
}
void sum( All *all, int *index, int n )
{
for( int i = 0; i < n; ++i, ++index )
all[*index].res = all[*index].a + all[*index].b;
}
class PerformanceTimer
{
public:
PerformanceTimer() { QueryPerformanceCounter( &start ); }
double time()
{
LARGE_INTEGER now, freq;
QueryPerformanceCounter( &now );
QueryPerformanceFrequency( &freq );
return double( now.QuadPart - start.QuadPart ) / double( freq.QuadPart );
}
private:
LARGE_INTEGER start;
};
int main( int argc, char* argv[] )
{
const int count = 10000000;
std::vector< float3 > a( count, float3{ 1.f, 2.f, 3.f } );
std::vector< float3 > b( count, float3{ 1.f, 2.f, 3.f } );
std::vector< float3 > res( count );
std::vector< All > all( count, All{ { 1.f, 2.f, 3.f }, { 1.f, 2.f, 3.f }, { 1.f, 2.f, 3.f } } );
std::vector< Both > both( count, Both{ { 1.f, 2.f, 3.f }, { 1.f, 2.f, 3.f } } );
std::vector< int > index( count );
int n = 0;
std::generate( index.begin(), index.end(), [&]{ return n++; } );
//std::random_shuffle( index.begin(), index.end() );
PerformanceTimer timer;
// uncomment version to test
//sum( &a[0], &b[0], &res[0], &index[0], count );
//sum( &both[0], &res[0], &index[0], count );
//sum( &all[0], &index[0], count );
std::cout << timer.time();
return 0;
}