【发布时间】:2013-07-06 02:46:00
【问题描述】:
我的问题基本上都在标题中,但让我详细说明一下。
问题:
也许值得改写一下,virtual 方法必须有多复杂/简单,才能使该机制成为相当大的开销?这有什么经验法则吗?例如。如果需要 10 分钟,使用 I/O、复杂的 if 语句、内存操作等,这不是问题。或者,如果你写virtual get_r() { return sqrt( x*x + y*y); };并循环调用它,你会遇到麻烦。
我希望这个问题不是太笼统,因为我寻求一些笼统但具体的技术答案。要么很难/不可能说出来,要么虚拟调用需要太多时间/周期资源,而数学需要这个,I/O 这个。
也许一些技术人员知道一些一般数字可以比较或进行一些分析,并可以分享一般性结论。尴尬的是我不知道如何让那些花哨的asm分析=/。
我还想给出一些背后的理由,以及我的用例。
我想我看到很多问题,人们为了性能而避免在干旱期间在森林中使用诸如明火之类的虚拟设备,以及许多人问他们“您是否绝对确定虚拟开销确实是一个问题你的情况呢?”。
我相信,在我最近的工作中,我遇到了一个可以放在河流两侧的问题。
还请记住,我不问如何改进接口的实现。我相信我知道该怎么做。我在问是否有可能告诉你什么时候做,或者选择哪一个。
用例:
我运行了一些模拟。我有一个基本上提供运行环境的类。有一个基类和多个定义一些不同工作流的派生类。 Base 收集东西作为通用逻辑并分配 I/O 源和接收器。衍生品或多或少通过实现RunEnv::run() 来定义特定的工作流程。我认为这是一个有效的设计。现在让我们想象作为工作流主题的对象可以放在 2D 或 3D 平面中。工作流在这两种情况下都是通用的/可互换的,因此我们正在处理的对象可以具有通用接口,尽管对于像Object::get_r() 这样的非常简单的方法。最重要的是,让我们为环境定义一些统计记录器。
最初我想提供一些代码 sn-ps,但它最终得到了 5 个类和 2-4 个方法,即code 的墙。我可以根据要求发布它,但它会将问题延长到当前大小的两倍。
关键点是:RunEnv::run()是主循环。通常很长(5mins-5h)。它提供基本的时间检测,调用RunEnv::process_iteration() 和RunEnv::log_stats()。都是虚拟的。理由是。我可以推导出RunEnv,例如针对不同的停止条件重新设计run()。我可以重新设计process_iteration(),例如,如果我必须处理对象池,则使用多线程,以各种方式处理它们。不同的工作流程也需要记录不同的统计数据。 RunEnv::log_stats() 只是一个调用,将已经计算出的有趣统计数据输出到 std::ostream 中。我猜使用虚拟并没有真正的影响。
现在假设迭代通过计算对象到原点的距离来工作。所以我们有接口double Obj::get_r();。 Obj 是 2D 和 3D 案例的实现。在这两种情况下,getter 都是一个简单的数学运算,包含 2-3 次乘法和加法。
我还尝试了不同的内存处理。例如。有时坐标数据存储在私有变量中,有时存储在共享池中,因此即使get_x() 也可以通过实现get_x(){return x;}; 或get_x(){ return pool[my_num*dim+x_offset]; }; 进行虚拟化。想象一下用get_r(){ sqrt(get_x()*get_x() + get_y()*get_y()) ;}; 计算一些东西。我怀疑这里的虚拟性会影响性能。
【问题讨论】:
-
sqrt()已经足够贵了,您可能感觉不到虚拟通话。 -
当一个讨厌虚拟调用的人正在审查代码时。
-
@Mysticial 这正是我正在寻找的。我从来没有看到一个答案说 vtable 查找与典型任务(如
sqrt()、O(1) int/float math、short for-loop、简单 I/O 等)相比实际开销有多大。跨度> -
既然您追求性能,是否可以不需要平方根?如果您要比较距离,或者将它们放入可以再次平方(即引力/电磁)的方程中,那么您可以完全避免平方根。
-
@Mysticial 我知道。我不想就根本问题及其实施提出问题。我刚刚研究过类似的东西,所以用它来做一个例子更容易。
标签: c++ performance