我目前在一个用C++授课的高性能计算课程中。通常,我在C#中工作,这意味着一切都由我来处理,而优化则是在可维护性和更高级别的特性之后。就像..。一个不错的生产力炉,使我在编程项目的冬天保持良好和温暖,而我的CPU周期/缓存错过电费。然而,现在我在C++和高效算法的土地,这些东西是次要的优化。
由于我的大部分工作都是在C#,面向对象编程是我的风格之一。然而,我越来越多地阅读/听说面向对象的代码是性能的敌人。当我对软件体系结构的理解从只关注类结构和封装转向理解如何从L1缓存和流水线处理事物时,我试图理解为什么面向对象的设计(特别是适用于C++)造成硬件资源浪费的真正原因。你们能给我一些基本的原因来解释为什么它会影响计算机性能吗?我知道还有其他关于OOP的争论,但我只想让它在硬件和算法级别上保持性能。
发布于 2014-02-09 19:45:02
OOP的许多性能问题来自于继承和虚拟方法所造成的间接问题。虚拟方法是有问题的,因为:
如果删除这一点,您将失去使用OOP的主要要点,比如模块化或可扩展性,但您将获得性能。C++的主要优点(特别是与C#和Java相比)是,您可以选择您希望这种间接的位置,以及您希望以非面向对象的方式进行操作的地方。您可以在C#中做到这一点,但这并不像在C++中那么好和容易。
发布于 2014-08-16 08:56:54
如前所述,虚拟函数会损害性能。这并不是因为v表查找非常快,而是因为丢失了内联的机会,这节省了函数调用的开销,并允许编译器跨越函数边界进行优化。但是请注意,在c++11中,'final‘关键字应该允许内联虚拟化。此外,这只是一个多态问题。在使用OOD时,并不总是使用多态性。
当前性能中最重要的事情之一是缓存丢失。在过去的几十年中,CPU和RAM之间的速度差异已经增长了很多。缓存丢失可能导致CPU在获取数据时等待超过200个周期。尽量减少这是一个复杂的主题,但是有一件事通常是个好主意:如果在关键路径上有一个紧密的循环,那么理想情况下,您希望访问的数据能够完全按顺序存储,不存在任何空白。CPU实际上相当聪明,并且会注意到您正在按顺序检索数据。这意味着它实际上将预取数据,并防止您丢失缓存,即使是在从未被请求的数据上!
然而,OOD将您推向一个特定的内存布局。例如,假设您有一个A类的对象,成员为x、y和z,这些都很重要。但是,程序的关键路径是对大量的A进行操作,只对成员x和y执行一些操作。这些z可能会损害您的性能,因为它们是存储中无用的空白。如果z是一个非常大的类型,这可能会大大增加分支失误。
请注意,如果您确实使用了多态性,那么上面的示例将变得更加可怕:而不是A的值数组,而是指向A的一系列指针,现在您的数据到处都是,这很糟糕。
在许多地方仍然可以使用OOD模式,但要注意到这些问题。例如,我多次使用的一种模式是生成"Op“对象。如果您有一个非常定义的关键路径,那么在此关键路径之前或之后的任何代码基本上都是免费的。如果你的A包含了很多重要的信息,例如,为了配置或设置的目的,最好是创建一个更精简的对象,只为关键路径中的循环创建一个必要的、适当排列的数据。我经常将这个类称为A_Op或类似类,并给出一个发出"Op“类的方法。
编辑:我不想在这里简单地提到模板。模板允许您执行类似的抽象OOD,但运行时间成本为零.一个众所周知的例子是编译时多态(在某种意义上不是真正的多态),通过奇怪的循环模板模式。或基于策略的设计。
发布于 2014-02-09 22:35:40
在进行任何类型的软件设计时,注意“过早优化”是很重要的。第一条规则是正确的。只有通过一组完整的单元测试才能确保正确性,才能考虑性能。
性能是通过测试实现的。一旦算法发挥作用,就测试它们,以确定是否需要额外的性能。
https://softwareengineering.stackexchange.com/questions/228327
复制相似问题