C++ 函数性能问题

Posted

技术标签:

【中文标题】C++ 函数性能问题【英文标题】:C++ function performance issue 【发布时间】:2018-03-29 04:28:15 【问题描述】:

我遇到了一个 ,使用下面的代码进行测试。 queryInterfacequeryInterface1 的实现几乎相同。唯一的区别是queryInterface调用classType函数,而classType函数调用classType1queryInterface1直接调用classType1queryInterface1 的性能很差,是queryInterface 的两倍。 queryInterface1 有什么问题,为什么?用 MSVC 编译。在控制台查看输出:

queryInterface() 的时间成本:2453

queryInterface1() 的时间成本:4961

#include <string>
#include <time.h>
#include <iostream>
#include <unordered_map>

using namespace std;

namespace

    int find(const string& name)
    
        return 0;
    

    class A
    
    public:
        static int classType();
        static int classType1();
        virtual void* queryInterface(int id) const
        
            if (A::classType() == id)
                return const_cast<A*>(this);

            return nullptr;
        
        virtual void* queryInterface1(int id) const
        
            if (A::classType1() == id)
                return const_cast<A*>(this);

            return nullptr;
        
    ;

    int A::classType()
    
        static int s_classType = classType1();
        return s_classType;
    

    int A::classType1()
    
        static int s_classType = find("A");
        return s_classType;
    


int main()

    clock_t start, stop;
    const size_t count = 1000000000;

    A* pA = new A;
    start = clock();
    for (size_t i = 0; i < count; i++)
    
        pA->queryInterface(A::classType());
    
    stop = clock();
    cout << "time cost of queryInterface(): " << stop - start << endl;

    start = clock();
    for (size_t i = 0; i < count; i++)
    
         pA->queryInterface1(A::classType1());
    
    stop = clock();
    cout << "time cost of queryInterface1(): " << stop - start << endl;

    return 0;

【问题讨论】:

你是怎么编译的?你启用优化了吗? find("A") 需要创建 std::string 对象,这会使调用变慢。 您是否多次运行每个版本? FWIW,我在 cygwin 下看不到 g++ 6.4.0 的模式。 @S.M.,优化选项设置为“最大化速度 (/O2)”。两者都应该调用一次 find("A"),因为它是由静态变量调用的。 @John3136,是的,我运行它们 1000000000 次。 【参考方案1】:

性能差异是由于编译器在A::classType1 的调用中设置了安全检查。每次调用都会设置这些,即使它只在调用 find 函数的一次真正需要。

安全检查确定堆栈是否已被覆盖,可能会破坏堆栈帧,包括返回地址。

如果将s_classType 的初始值更改为常量整数,而不是调用find,则可以更快地执行queryInterface1 调用。

可以使用/GS- 编译器选项禁用安全检查。

【讨论】:

你的意思是改变 A::classType1 如下?这不是更好。 int A::classType1() 静态 int s_classType = -1; if (s_classType == -1) s_classType = find("A"); 返回 s_classType; @ldlchina 不,我完全消除了对find 的调用(static int s_classType = 17;)。您需要将对 find 的调用放入另一个函数中以避免异常处理程序的惩罚。 喜欢 A:classType?如果是这样,那让我很紧张,什么时候需要这样做?规则是什么?谢谢。 @1201ProgramAlarm @ldlchina 是的,比如A::classType。如果静态初始化表达式做了一些可能需要异常处理程序的事情,而函数的其余部分却不需要,那么你会想要这样做。 为什么A::classType() 不会发生这种情况?

以上是关于C++ 函数性能问题的主要内容,如果未能解决你的问题,请参考以下文章

左值的 C++ std::move() 性能明智

C++:对象、对对象的引用、对带有和不带有函数的向量元素的引用——观察到的性能差异

C++性能榨汁机之虚函数的开销

如何正确使用函数形参提高C++程序性能

性能提升:使用c#调用c++(核心代码优化)

C++访问lua函数性能测试结果