Boost.Variant与虚拟接口性能

时间:2012-08-10 17:46:40

标签: performance boost interface virtual variant

我正在尝试测量使用Boost.Variant和使用虚拟接口之间的性能差异。例如,假设我想统一增加不同类型的数字,使用Boost.Variant我将使用boost :: variant而不是int和float以及一个静态访问者,它们会增加每一个。使用类接口我将使用纯虚拟类号和number_int以及number_float类,它们从中派生并实现“增量”方法。

从我的测试来看,使用接口比使用Boost.Variant要快得多。 我在底部运行代码并收到这些结果:
虚拟:00:00:00.001028
变式:00:00:00.012081

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

**注意:通常Boost.Variant使用堆分配来保证变量始终为非空。但我在Boost.Variant文档中读到,如果boost :: has_nothrow_copy为true,那么它不会使用堆分配,这应该会使事情显着加快。对于int和float boost :: has_nothrow_copy为true。

以下是我测量两种方法的代码。

#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;
}

2 个答案:

答案 0 :(得分:15)

对于那些感兴趣的人,在我有点沮丧之后,我将选项-O2传递给编译器,而boost :: variant比虚拟调用更快。
感谢

答案 1 :(得分:4)

很明显,-O2减少了变体时间,因为整个循环被优化掉了。更改实现以将累积结果返回给调用者,以便优化器不会删除循环,并且您将获得真正的区别:

输出:
虚拟:00:00:00.000120 = 10000000
变式:00:00:00.013483 = 10000000

#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;
}
相关问题