标题中基本上完全阐明了我的问题,但让我详细说明。
问题:
也许值得改写,virtual
方法必须多么复杂/简单,才能使该机制产生相当大的开销?是否有任何经验法则?例如。如果花费10分钟,则使用I/O,复杂的if
语句,内存操作等,这不是问题。或者,如果您编写virtual get_r() { return sqrt( x*x + y*y); };
并在循环中调用它,则会遇到麻烦。
我希望这个问题不是太笼统,因为我寻求一些一般但具体的技术答案。它要么很难/不可能说出,要么虚拟调用花费了很多时间/占用了资源,而数学花费了这个,I/O了。
也许有些技术人员知道一些通用数字可以比较或进行了一些分析,并且可以共享一些通用结论。令人尴尬的是,我不知道如何使这些花哨的asm
分析=/。
我还想提供一些依据,以及我的用例。
我想我看到了很多问题,人们出于性能的考虑而避免在干旱期间使用像森林中的明火这样的虚拟对象,还有很多人问他们:“您绝对确定虚拟开销确实是您遇到的问题吗? ?”。
我相信,在最近的工作中,我遇到了一个问题,这个问题可以摆在河的两边。
还请记住,我不问如何改善接口(interface)的实现。我相信我知道该怎么做。我在问是否有可能告诉何时做,或选择哪种做对。
用例:
我进行一些模拟。我有一个基本上提供运行环境的类。有一个基类,一个以上的派生类定义了一些不同的工作流程。 Base收集东西作为通用逻辑并分配I/O源和接收器。衍生物通过实现RunEnv::run()
或多或少地定义了特定的工作流程。我认为这是一个有效的设计。现在,让我们想象一下可以将工作流主题的对象放置在2D或3D平面中。在这两种情况下,工作流都是通用的/可互换的,因此,尽管像Object::get_r()
这样的非常简单的方法,我们正在处理的对象仍可以具有通用的接口(interface)。最重要的是,让我们为环境定义一些状态记录器。
最初我想提供一些代码片段,但最终得到5个类和2-4个方法,即code
墙。我可以应要求将其发布,但是它将把问题延长到当前大小的两倍。
关键点是:RunEnv::run()
是主循环。通常很长(5分钟-5小时)。它提供了基本的时间检测功能,分别调用RunEnv::process_iteration()
和RunEnv::log_stats()
。全部都是虚拟的。理由是。我可以派生RunEnv
,例如针对不同的停止条件重新设计run()
。我可以重新设计process_iteration()
,例如在必须处理对象池,以各种方式处理它们的情况下使用多线程。同样,不同的工作流程将需要记录不同的统计信息。 RunEnv::log_stats()
只是将已计算出的有趣统计数据输出到std::ostream
中的调用。我想使用虚拟技术并没有真正的影响。
现在,假设迭代通过计算对象到原点的距离来实现。因此,我们将double Obj::get_r();
作为接口(interface)。 Obj
是2D和3D情况的实现。在两种情况下, setter/getter 都是带有2-3个乘法和加法的简单数学。
我还尝试了不同的内存处理。例如。有时坐标数据存储在私有(private)变量中,有时存储在共享池中,因此即使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()) ;};
计算某些内容。我怀疑这里的虚拟性会降低性能。
最佳答案
x86上C++中的虚拟方法调用产生类似于(单继承)的代码:
mov ecx,[esp+4]
mov eax,[ecx] // pointer to vtable
jmp [eax]
与非虚拟成员函数相比,如果没有虚拟成员,您将保留一条
mov
指令。因此,在单继承的情况下,性能影响可忽略不计。如果您有多个继承,或者更糟的是虚拟继承,则虚拟调用可能要复杂得多。但这是类层次结构和体系结构的更多问题。
经验法则:
如果该方法的主体比单个
mov
指令慢许多倍(> 100x),则只需使用virtual
即可,不要打扰。否则-设定瓶颈并进行优化。更新:
对于多重/虚拟继承案例,请查看此页面:http://www.lrdev.com/lr/c/virtual.html