代码之家  ›  专栏  ›  技术社区  ›  MOnsDaR

动态演员表演?

  •  39
  • MOnsDaR  · 技术社区  · 15 年前

    在阅读问题之前:
    dynamic_cast . 这只是它的表现。

    我最近开发了一个设计 经常使用。
    当和同事讨论时,几乎每个人都这么说 动态铸造

    我决定测试这个方法的性能,而不是仅仅相信它们。

    使用了以下代码:

    ptime firstValue( microsec_clock::local_time() );
    
    ChildObject* castedObject = dynamic_cast<ChildObject*>(parentObject);
    
    ptime secondValue( microsec_clock::local_time() );
    time_duration diff = secondValue - firstValue;
    std::cout << "Cast1 lasts:\t" << diff.fractional_seconds() << " microsec" << std::endl;
    

    上面的代码使用来自 boost::date_time 在Linux上获取可用值。
    我做了3个 在一次执行中,测量它们的代码是相同的。

    执行1次的结果如下:
    Cast1持续时间:74微秒
    Cast2持续时间:2微秒

    第一个cast始终采用74-111 microsec,以下cast在同一执行中采用1-3 microsec。

    最后我的问题是:
    动态铸造 真的表现不好?

    为什么这么多的开发人员认为如果不是的话会很慢呢?

    4 回复  |  直到 10 年前
        1
  •  52
  •   Oliver Charlesworth    15 年前

    首先,您需要在很多次迭代中测量性能,因为您的结果将由计时器的分辨率控制。尝试100万以上,以建立一个具有代表性的图片。同样,除非你将这个结果与某件事进行比较,即做相同的事,但不进行动态铸造,否则这个结果是没有意义的。

    其次,您需要通过优化同一指针上的多个动态强制转换来确保编译器不会给出错误的结果(因此使用循环,但每次使用不同的输入指针)。

    NULL . 所有这些都需要循环。

        2
  •  30
  •   Roger Pate Roger Pate    15 年前

    如果不比较等效功能,性能就毫无意义。 大多数人说,如果不与同等的行为相比,动态演算是慢的。把他们叫出来。换一种说法:

    如果不需要“works”,我可以编写比您的代码更快失败的代码。

    primes to improve dynamic_cast ,例如。不幸的是,控制编译器如何实现强制转换是不寻常的,但是如果性能对您真的很重要,那么您可以控制您使用的编译器。

    不使用 动态铸造遗嘱 总是

        3
  •  21
  •   VladV    14 年前

    以下是一些基准:
    http://tinodidriksen.com/2010/04/14/cpp-dynamic-cast-performance/
    http://www.nerdblog.com/2006/12/how-slow-is-dynamiccast.html

    根据他们的说法,dynamic_cast比reinterpret_cast慢5-30倍,最好的替代方案的性能几乎与reinterpret_cast相同。

    我将引用第一篇文章的结论:

    • dynamic_cast对于除了基础类型以外的任何类型都很慢;即 优化了特定的铸件
    • 继承级别对动态转换有很大影响
    • 成员变量+重新解释强制转换是最快可靠的方法
      确定类型;但是,它有更高的维护开销
      编码时

        4
  •  6
  •   Eugene Smith    15 年前

    很抱歉这么说,但是你的测试对于判断演员的表演是否慢是毫无用处的。微秒的分辨率远远不够好。我们说的是一种操作,即使在最坏的情况下,在一台典型的个人电脑上也不应该超过,比如说,100个时钟周期,或者少于50纳秒。

    毫无疑问,动态强制转换将比静态强制转换或重新解释强制转换慢,因为在程序集级别,后两个强制转换相当于一个赋值(非常快,顺序是1个时钟周期),而动态强制转换需要代码去检查对象以确定其真实类型。

    我不能马上说它有多慢,这可能会因编译器而异,我需要看到为那一行代码生成的汇编代码。但是,就像我说的,每次调用50纳秒是期望合理值的上限。

        5
  •  3
  •   greggo    6 年前

    你的里程数可能会有所不同,以低估情况。

    dynamic_cast的性能在很大程度上取决于您在做什么,并且可以取决于类的名称是什么(以及比较相对于 reinterpet_cast 似乎很奇怪,因为在大多数情况下,出于实际目的不需要任何指令,例如 unsigned int ).

    我一直在研究它在clang/g++中是如何工作的。假设你是 dynamic_cast 从一个 B* 给一个 D* B 是(直接或间接)的 D ,并且不考虑多个基类的复杂性,它似乎通过调用库函数来工作,该函数执行如下操作:

    for dynamic_cast<D*>(  p  )   where p is B*
    
    type_info const * curr_typ = &typeid( *p );
    while(1) {
         if( *curr_typ == typeid(D)) { return static_cast<D*>(p); } // success;
         if( *curr_typ == typeid(B)) return nullptr;   //failed
         curr_typ = get_direct_base_type_of(*curr_typ); // magic internal operation
    }
    

    所以,是的,当 *p 实际上是 ;只有一个成功的 type_info 最糟糕的情况是当演员失败时 ;在这种情况下,有很多失败的类型比较。

    类型比较需要多长时间?它做到了,在clang/g++:

    compare_eq( type_info const &a, type_info const & b ){
       if( &a == &b) return true;   // same object
       return strcmp( a.name(), b.name())==0;
    }
    

    需要strcmp,因为可能有两个不同的 键入信息 成功的 类型比较非常快。

    name() 所以还有另一个因素:如果很多课程都是从 名字以开头 MyAppNameSpace::AbstractSyntaxNode< ,则失败的比较将花费比通常更长的时间;strcmp将不会失败,直到它在损坏的类型名称中达到差异。

    当然,由于操作作为一个整体正在遍历一堆表示类型层次结构的链接数据结构,因此时间将取决于这些内容在缓存中是否新鲜。因此,重复执行同一个cast可能会显示一个平均时间,这不一定代表该cast的典型性能。