我正在开发我的第一个C ++项目,这是一个CSV解析器(full source code here)。它正处于工作状态,现在我想进行基本的重构/提高性能。
目前解析器的工作方式是将每一行作为std::vector<std::string>
返回,我认为每次我只有一个内部向量和内部时,而不是分配一个新的向量和一个新的字符串我保留记忆的字符串,我一次又一次地清除。
这很有用,我开始查看我可能正在进行内存分配的其他地方,我看到了这个复制内部向量的函数,然后将其清除:
auto add_row() -> std::vector<std::string> {
auto row(m_bufvec);
m_bufvec.clear();
return row;
}
我认为如果我改变了这一行
auto row(m_bufvec);
到
auto row(std::move(m_bufvec));
它会导致某种速度提升,因为根据http://en.cppreference.com/w/cpp/container/vector/vector,它需要恒定的时间而不是线性的。令我惊讶的是,它使解析器显着变慢(根据我在time ./main.o
上运行std::move
的非常粗略的基准)。
我对优化,基准测试以及调优C ++代码所带来的一切都是全新的。也许这种优化即使有效也没用,但无论如何,我很好奇//renderer
renderer = new THREE.WebGLRenderer( { canvas : spaceCanvas} );
renderer.setSize( 672, 472 );
renderer.shadowMap.enabled = true;
renderer.shadowMap.renderReverseSided = false;
//mainScene
mainScene = new THREE.Scene();
mainCamera = new THREE.PerspectiveCamera( 45, window.innerWidth /window.innerHeight, 0.01, 2000 );
mainCamera.position.z = 2.25;
//Lighting
var ambLight = new THREE.AmbientLight( 0x222222 );
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set(5,3,5);
light.castShadow = true;
light.shadow.camera.near = 0.01;
light.shadow.camera.far = 15;
light.shadow.camera.fov = 45;
light.shadow.camera.left = -1;
light.shadow.camera.right = 1;
light.shadow.camera.top = 1;
light.shadow.camera.bottom = -1;
/*light.shadowCameraVisible = true;*/
light.shadow.bias = 0.001;
light.shadow.mapSize.width = 672;
light.shadow.mapSize.height = 472;
mainScene.add(light, ambLight);
导致经济放缓的原因。我错过了什么吗?
答案 0 :(得分:8)
复制bufvec时,其容量不变,但移动时,其容量将被清除。因此,稍后当你填写bufvec时,会进行对数的分配以再次扩展其容量,这样的分配很容易成为你的性能瓶颈。
移动版本使 功能更快。但它使其他代码变慢。微优化不能可靠地使程序更快。
OP编辑:
Cheers and hth. - Alf
在移动后m_bufvec.reserve(row.size())
的评论中提出的解决方案解决了问题,并确认上述推理是正确的。此外,它更有效率(虽然只是略微),因为
你避免复制[在bufvec中]的项目。如果项目是简单的整数值,那么这并不重要。如果物品是例如字符串,动态分配,那真的很重要。
答案 1 :(得分:1)
确实第一个版本预计会更快。原因是:
auto row(m_bufvec);
调用copy constuctor,它立即为row
分配必要的内存。 bufvec
也保留其分配的内存。因此,分配 per-element 最小化,这很重要,因为它们涉及大量的重定位。
在第二个版本中,auto row(std::move(m_bufvec));
bufvec
的内存由row
拥有,此操作比复制构造函数更快。但是当bufvec
丢失了已分配的内存时,当您稍后逐个元素填充它时,它将执行许多重新分配和(昂贵的)重定位。重新分配的数量通常与矢量的最终大小成对数。
修改
以上解释了主要问题中的“意外”结果。最后,事实证明,此操作的“理想”是移动然后立即保留:
auto row(std::move(m_bufvec);
m_bufvec.reserve(row.size());
return row;
这实现了三个目标:
没有按元素分配
bufvec
不会将m_bufvec
中的元素无用地复制到row
。