Próbuję zmierzyć różnicę wydajności między korzystaniem z Boost.Variant i wirtualnymi interfejsami. Na przykład, przypuśćmy, że chcę zwiększać różne typy liczb równomiernie, używając Boost.Variant, użyłbym boost :: variant over int i float oraz statycznego gościa, który inkrementuje każdy z nich. Korzystając z interfejsów klas, używałbym czystego wirtualnego numeru klasy oraz klas number_int i number_float, które wywodzą się z niego i implementują metodę "inkrementacji".
Z moich testów korzystanie z interfejsów jest znacznie szybsze niż przy użyciu metody Boost.Variant. Pobiegłem kod na dole i otrzymał następujące wyniki:
wirtualna: 00: 00: 00,001028
Wariant: 00: 00: 00,012081
Wydajność wirtualnego interfejsu Boost.Variant Vs
Jak myślisz, dlaczego ta różnica jest? Myślałem, że Boost.Variant będzie o wiele szybszy.
** Uwaga: Zazwyczaj Boost.Variant używa alokacji sterty, aby zagwarantować, że wariant będzie zawsze niepusty. Ale czytałem w dokumentacji Boost.Variant, że jeśli boost :: has_nothrow_copy jest prawdziwe, to nie używa alokacji sterty, co powinno znacznie przyspieszyć działanie. Dla int i float boost :: has_nothrow_copy jest prawdziwe.
Oto mój kod do mierzenia obu podejść względem siebie.
#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;
}
Dzięki za zamieszczenie follow-up, jestem zainteresowany! –
Jakie były twoje wyniki i jaki kompilator? Korzystanie z Boost 1.52 i Mingw 4.7 Dostaję wariant jest około 8 razy wolniejszy w trybie zwolnienia. O dziwo, '-O2' jest nieco szybsze niż' -O3';/ – AbstractDissonance
Używam g ++ 4.7 i nie jestem pewien, która wersja boost, ale prawdopodobnie 1.5x. Podałem -O2 do kompilatora, a moje wyniki: Wirtualny: 00: 00: 00.018806 Wariant: 00: 00: 00.000001 W większości przypadków uzyskałbym 00:00:00 w wariancie, więc ustawiłem iterations_count na 10000000 Używam tego testu na procesorze Intel Core i7 2,8 GHz. –