提问人:cppBeginner 提问时间:9/11/2017 最后编辑:cppBeginner 更新时间:9/11/2017 访问量:50
使 2 个非静态字段(即动态数组)彼此靠近地使用内存
Make 2 non-static fields (that are dynamic arrays) use memory near each other
问:
让 和 成为动态大小的存储类。
(例如B1
B2
B1~std::vector<char>
B2~std::vector<float>
)
在 C++ 11 中,如果我编码和 's 和 函数(五法则),默认情况下,将它们作为字段包含的类将自动正确复制/移动。B1
B2
move
copy
C
class C{
B1 b1; B2 b2;
};
它工作得很好。
问题
今天,我得到了配置文件结果+做了一些关于性能问题的测试。
主要目标:我必须使和相同的实例在彼此附近分配内存:-b1
b2
C
b1[0] b1[1] ... b1[b1.size-1] (minimum gap) b2[0] b2[1] ... b2[b2.size-1]
如果可以的话,我将在整个程序中获得 10-20% 的性能提升。
我可怜的解决方案
我可以使用这样的自定义分配器(伪代码):-
class C{
B1 b1;
B2 b2;
Allocator* allo_; // can be heap allocator
public: void reserve(int size){
//old : b1.reserve(size); b2.reserve(size); .... so easy
//new :-
B1 b1Next; B2 b2Next;
int nb1=b1Next.howMuchIWant(size);
int nb2=b2Next.howMuchIWant(size);
//^ request amount of bytes needed if capacity="size"
void* vPtr=allo_->allocate(nb1+nb2);
b1Next.setMemory(vPtr);
b2Next.setMemory(vPtr + nb1); //add "vPtr" by "nb1" bytes
b1Next=b1; //copy assignment (not move memory)
b2Next=b2; //copy assignment (not move memory)
b1=std::move(b1Next); //move memory
b2=std::move(b2Next); //move memory
//clean up previous "vPtr" (not shown)
}
};
它可以工作,但代码变得更难调试/维护。更不用说移动和复制了。C
在旧版本中,all / mess 仅出现在 和 中。
现在,混乱出现在每个使用数据结构的类中,就像 和 直接一样。copy
move
B1
B2
B1
B2
问题
有哪些 C++ 技术/设计模式/习语可以提供帮助?
要回答这个问题,不需要任何可运行的代码。伪代码或只是一个概念就足够了。
我很遗憾没有提供MCVE。
自定义分配器和阵列管理是真正难以最小化的事情。
答:
1赞
nh_
9/11/2017
#1
改善数据局部性的一种可能性是从 a of s 变为 a of s。而不是struct
vector
vector
struct
struct S
{
std::vector<char> c;
std::vector<int> i;
};
S data;
使用
struct S
{
char c;
int i;
};
std::vector<S> data;
这样,数据始终存储在一起,您无需修改自定义分配器。这是否适用于您的情况主要取决于两个条件:
- 是否有必要拥有所有(或)连续的?例如,因为定期调用 API 需要相应类型的 API。
char
int
vector
- 存储的数量是否相等(至少几乎相等)?
char
int
评论
0赞
cppBeginner
9/11/2017
就我而言,由于您已经提到的原因,我无法使用它。(它们的大小不相等,必须是连续的,数据局部性和缓存未命中问题等)但是谢谢!如果我变得绝望,这是个好主意。i
0赞
nh_
9/11/2017
@cppBeginner 在执行过程中,和 的数量是否发生了巨大变化?和 是否有任何估计的边界?而且,两者的顺序是否重要?int
char
c.size()
i.size()
i
c
0赞
cppBeginner
9/11/2017
这很难回答。我有许多具有此症状的自定义数据结构,例如 SparseMap<T>
、、.它们彼此如此不同。它们具有共同的功能,如果需要,还可以提供自动生长1->2->4->8。其自身数组内的顺序通常很重要,但数组和数组之间的顺序并不重要。SetOfInt
SimpleArray<T>
reserve(int size)
i
c
i
c
0赞
nh_
9/11/2017
@cppBeginner 恐怕如果您需要最佳性能,解决方案将在某种程度上针对特定问题量身定制,并且通常不适用。我正在考虑一个连续的字节数组,它被分成两半,使得 s 从前面到中间增长,而 s 从中间到结尾增长。但很难说这是否有益,因为如果数字定期变化,重新分配可能经常是必要的。i
c
0赞
cppBeginner
9/11/2017
我目前喜欢这个。如果我从 开始,那么我加上 ,它将变成 。性能已经足够好了。我的问题主要是关于代码的可维护性/可重用性。我已经使用和放置新的,而且速度非常快。:)[c0,c1,i0,i1]
c2
[c0,c1,c2,-,i0,i1,-,-]
char[]
评论
char
int
vector
vector
uint8_t
C
B1
B1
B2
reserve()
b1
b2
C