2012-08-10 35 views
8

我试图衡量使用Boost.Variant和使用虚拟接口之间的性能差异。例如,假设我想要使用Boost.Variant来统一增加不同类型的数字,我会在int和float上使用boost :: variant,并使用静态访问器来增加它们中的每一个。使用类接口我会使用一个纯虚拟类号和number_int和number_float类,它们派生自它并实现“增量”方法。

从我的测试中,使用接口比使用Boost.Variant快得多。 我跑在底部的代码,并获得这些结果:
虚拟:00:00:00.001028
变:00:00:00.012081
Boost.Variant与虚拟接口性能

,你为什么认为这种差异是什么?我认为Boost.Variant会更快。

**注意:通常Boost.Variant使用堆分配来保证变体总是非空的。但是我阅读了Boost.Variant文档,如果boost :: has_nothrow_copy是真的,那么它不会使用堆分配,这会使事情显着加快。对于int和float boost :: has_nothrow_copy是真的。

这是我的代码,用于测量两种方法相互对抗。

#include <iostream> 

#include <boost/variant/variant.hpp> 
#include <boost/variant/static_visitor.hpp> 
#include <boost/variant/apply_visitor.hpp> 

#include <boost/date_time/posix_time/ptime.hpp> 
#include <boost/date_time/posix_time/posix_time_types.hpp> 
#include <boost/date_time/posix_time/posix_time_io.hpp> 

#include <boost/format.hpp> 

const int iterations_count = 100000; 

// a visitor that increments a variant by N 
template <int N> 
struct add : boost::static_visitor<> { 
    template <typename T>  
    void operator() (T& t) const { 
     t += N; 
    } 
}; 

// a number interface 
struct number {   
    virtual void increment() = 0; 
}; 

// number interface implementation for all types 
template <typename T> 
struct number_ : number { 
    number_(T t = 0) : t(t) {} 
    virtual void increment() { 
     t += 1; 
    } 
    T t; 
}; 

void use_virtual() { 
    number_<int> num_int; 
    number* num = &num_int; 

    for (int i = 0; i < iterations_count; i++) { 
     num->increment(); 
    } 
} 

void use_variant() { 
    typedef boost::variant<int, float, double> number; 
    number num = 0; 

    for (int i = 0; i < iterations_count; i++) { 
     boost::apply_visitor(add<1>(), num); 
    } 
} 

int main() { 
    using namespace boost::posix_time; 

    ptime start, end; 
    time_duration d1, d2; 

    // virtual 
    start = microsec_clock::universal_time(); 
    use_virtual(); 
    end = microsec_clock::universal_time(); 

    // store result 
    d1 = end - start; 

    // variant 
    start = microsec_clock::universal_time(); 
    use_variant(); 
    end = microsec_clock::universal_time(); 

    // store result 
    d2 = end - start; 

    // output 
    std::cout << 
     boost::format(
      "Virtual: %1%\n" 
      "Variant: %2%\n" 
     ) % d1 % d2; 
} 

回答

14

对于那些有兴趣,我有点沮丧之后,我通过选项-O2编译器和boost ::变种比虚拟呼叫方式更快。
谢谢

+0

感谢张贴的后续,我很感兴趣! – 2012-10-30 04:00:29

+0

你的结果和编译器是什么?使用Boost 1.52和Mingw 4.7,我发现变体在释放模式下慢了大约8倍。奇怪的是'-O2'比'-O3'略快;/ – AbstractDissonance 2012-11-25 12:15:18

+0

我使用的是g ++ 4.7,我不知道是什么Boost版本,但它可能是1.5x。我将-O2传递给编译器,结果如下: 虚拟:00:00:00.018806 变体:00:00:00.000001 大多数情况下,我会在变体上获取00:00:00,因此我将iterations_count设置为1000000 我在2.8Ghz Intel Core i7 CPU上运行这个测试。 – 2012-11-26 12:25:37

4

很明显,-O2减少了变异时间,因为整个循环被优化了。更改实施积累的结果返回给调用者,以便优化程序不会消除环路,你会得到真正的区别在于:

输出:
虚拟:00:00:00.000120 =千万
变:00:00:00.013483 =千万

#include <iostream> 

#include <boost/variant/variant.hpp> 
#include <boost/variant/static_visitor.hpp> 
#include <boost/variant/apply_visitor.hpp> 

#include <boost/date_time/posix_time/ptime.hpp> 
#include <boost/date_time/posix_time/posix_time_types.hpp> 
#include <boost/date_time/posix_time/posix_time_io.hpp> 

#include <boost/format.hpp> 

const int iterations_count = 100000000; 

// a visitor that increments a variant by N 
template <int N> 
struct add : boost::static_visitor<> { 
    template <typename T> 
    void operator() (T& t) const { 
     t += N; 
    } 
}; 

// a visitor that increments a variant by N 
template <typename T, typename V> 
T get(const V& v) { 
    struct getter : boost::static_visitor<T> { 
     T operator() (T t) const { return t; } 
    }; 
    return boost::apply_visitor(getter(), v); 
} 

// a number interface 
struct number { 
    virtual void increment() = 0; 
}; 

// number interface implementation for all types 
template <typename T> 
struct number_ : number { 
    number_(T t = 0) : t(t) {} 
    virtual void increment() { t += 1; } 
    T t; 
}; 

int use_virtual() { 
    number_<int> num_int; 
    number* num = &num_int; 

    for (int i = 0; i < iterations_count; i++) { 
     num->increment(); 
    } 

    return num_int.t; 
} 

int use_variant() { 
    typedef boost::variant<int, float, double> number; 
    number num = 0; 

    for (int i = 0; i < iterations_count; i++) { 
     boost::apply_visitor(add<1>(), num); 
    } 

    return get<int>(num); 
} 
int main() { 
    using namespace boost::posix_time; 

    ptime start, end; 
    time_duration d1, d2; 

    // virtual 
    start = microsec_clock::universal_time(); 
    int i1 = use_virtual(); 
    end = microsec_clock::universal_time(); 

    // store result 
    d1 = end - start; 

    // variant 
    start = microsec_clock::universal_time(); 
    int i2 = use_variant(); 
    end = microsec_clock::universal_time(); 

    // store result 
    d2 = end - start; 

    // output 
    std::cout << 
     boost::format(
      "Virtual: %1% = %2%\n" 
      "Variant: %3% = %4%\n" 
     ) % d1 % i1 % d2 % i2; 
} 
+3

这还不是显示虚拟速度快2个数量级吗? – 2015-07-28 14:22:15

+0

你确定编译器不是虚拟化吗? – Brahim 2016-08-09 08:16:32