gpt4 book ai didi

用于更快创建新对象的 C++ block 分配器

转载 作者:行者123 更新时间:2023-11-30 01:51:39 25 4
gpt4 key购买 nike

我有一段代码可以创建数千个对象,并将它们附加到一个 vector 中。下面的代码只是一个正在做的事情的例子,尽管构造函数有一些参数,而for实际上并没有那个条件,但它起到了表明它运行了数千次的目的。

vector<VolumeInformation*> vector = vector<VolumeInformation*>();
for (int i = 0; i < 5000; ++i) {
VolumeInformation* info = new VolumeInformation();
vector.push_back(info);
}

代码运行需要很长时间,我试图找到一种更快的方法来创建所有对象。我阅读了有关 block 分配器的信息,但我不确定这是否真的适用于我正在尝试做的事情,以及它是否真的有助于更快地完成这项工作。我想为一千个对象分配内存(例如),并在它仍然可用时继续使用该内存,然后在需要时分配更多内存,避免每次都为单个对象分配内存。这可以做到吗?你能给我指出一个地方,在那里我可以找到一个关于如何告诉"new"使用以前分配的内存的例子吗?如果不是对象本身,分配器是否可以用于 vector 的内存(即使对象才是真正需要加速的)?

谢谢。

**更新**

在所有的回答和评论之后,我决定更改代码,这样 vector 将存储对象而不是指针,这样我就可以使用 reserve 为 vector 预分配一些内存,从而节省一些通过一次为多个对象实例分配内存来节省时间。虽然,在做了一些性能基准测试之后,我确认我所做的更改性能更差,除非我提前知道 vector 的确切大小。这是我的发现,我想知道是否有人可以阐明这一点,让我知道为什么会发生这种情况,如果我在这里遗漏了什么,或者我之前使用的方法是否真的是最好的方法。

这是我用于基准测试的代码:

    vector<int> v = vector<int>();
v.push_back(1);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(7);
v.push_back(9);

int testAmount = 200000;
int reserve = 500000;

Stopwatch w = Stopwatch();





w = Stopwatch();
vector<VolumeInformation> infos = vector<VolumeInformation>();
infos.reserve(reserve);
for (int i = 0; i < testAmount; ++i) {
infos.emplace_back(&v, 1, 0, 0);
}
int elapsed = w.Elapsed();






w = Stopwatch();
vector<VolumeInformation*> infoPointers = vector<VolumeInformation*>();
infoPointers.reserve(reserve);
for (int i = 0; i < testAmount; ++i) {
infoPointers.emplace_back(new VolumeInformation(&v, 1, 0, 0));
}
int elapsed2 = w.Elapsed();

如果我注释掉两行 reserve() ,没有指针的版本需要 32.701 秒,而指针版本需要 6.159 秒!它比使用对象 vector 少 5 倍以上。

如果我使用保留,但将要保留的项目数量设置为低于迭代次数的值,对象版本的 vector 仍然比指针版本花费更多时间。

如果我使用大于或等于迭代次数的值保留,对象版本的 vector 会变得更快,只需要 270 毫秒,而指针版本需要 8.901 秒。这里的主要问题是我事先不知道 vector 将达到的大小,因为迭代不是基于硬编码数字,这只是为了进行基准测试。

有人可以解释为什么会发生这种情况,是否有其他解决方法,或者我在这里做错了什么?

最佳答案

vector完全有能力预分配一个大块并将其用于所有元素,如果您正确使用它:

// create 5000 default-constructed X objects
std::vector<X> v(5000);

或者如果您需要传递构造函数参数:

std::vector<X> v;
v.reserve(5000); // allocate block of memory for 5000 objects
for (int i=0 ; i < v.size(); ++i)
v.emplace_back(arg1, arg2, i % 2 ? arg3 : arg4);

最后一行构造了一个X在预分配的内存中,没有复制,将函数参数传递给 X 构造函数。

I would want to allocate memory for a thousand objects (for example), and keep on using that memory while it is still available, and then allocate some more when needed, avoiding having to allocate memory for a single object every time.

std::vector自动执行此操作,您可能应该停止使用 new并且只有一个 vector<VolumeInformation>并直接将对象放入其中,而不是分配单个对象并存储指向它们的指针。

内存分配很慢(参见 Why should C++ programmers minimize use of 'new'? ),因此停止分配单个对象。上面的两个示例都将执行 1 分配和 5000 次构造函数调用。您的原始代码至少执行 5001 次分配和 5000 次构造函数调用(在典型的 C++ 实现中,它会执行 5013 次分配 和 5000 次构造函数调用)。

** 更新 **

If I comment out both reserve() lines, the version without pointers takes 32.701 seconds, while the pointer version takes 6.159! It takes 5+ times less than using a vector of objects.

因为你实际上并没有展示一个完整的工作程序,你要求人们猜测(总是展示实际代码!)但它表明你的类有一个非常慢的复制构造函数,它是当 vector 增长并且现有元素需要复制到新内存时使用(然后旧元素被销毁)。

如果可以加一个noexcept然后移动比复制构造函数更有效的构造函数 std::vector当 vector 需要增长并且运行得更快时将使用它。

The main issue here is that I do not know in advance the size that the vector will reach, as the iterations are not based in a hardcoded number, this was only to do the benchmarking.

您可以只保留比您可能需要的元素更多的元素,以更高的内存使用量换取更好的性能。

关于用于更快创建新对象的 C++ block 分配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25851365/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com