如果您需要速度,請考慮在對象中嵌入「type(-identifying)number」,並使用switch語句選擇類型特定的代碼。這可以完全避免函數調用開銷 - 只是進行本地跳轉。你不會比這更快。成本(就可維護性,重新編譯依賴性等而言)是強制特定類型功能的本地化(在交換機中)。
實現
#include <iostream>
#include <vector>
// virtual dispatch model...
struct Base
{
virtual int f() const { return 1; }
};
struct Derived : Base
{
virtual int f() const { return 2; }
};
// alternative: member variable encodes runtime type...
struct Type
{
Type(int type) : type_(type) { }
int type_;
};
struct A : Type
{
A() : Type(1) { }
int f() const { return 1; }
};
struct B : Type
{
B() : Type(2) { }
int f() const { return 2; }
};
struct Timer
{
Timer() { clock_gettime(CLOCK_MONOTONIC, &from); }
struct timespec from;
double elapsed() const
{
struct timespec to;
clock_gettime(CLOCK_MONOTONIC, &to);
return to.tv_sec - from.tv_sec + 1E-9 * (to.tv_nsec - from.tv_nsec);
}
};
int main(int argc)
{
for (int j = 0; j < 3; ++j)
{
typedef std::vector<Base*> V;
V v;
for (int i = 0; i < 1000; ++i)
v.push_back(i % 2 ? new Base : (Base*)new Derived);
int total = 0;
Timer tv;
for (int i = 0; i < 100000; ++i)
for (V::const_iterator i = v.begin(); i != v.end(); ++i)
total += (*i)->f();
double tve = tv.elapsed();
std::cout << "virtual dispatch: " << total << ' ' << tve << '\n';
// ----------------------------
typedef std::vector<Type*> W;
W w;
for (int i = 0; i < 1000; ++i)
w.push_back(i % 2 ? (Type*)new A : (Type*)new B);
total = 0;
Timer tw;
for (int i = 0; i < 100000; ++i)
for (W::const_iterator i = w.begin(); i != w.end(); ++i)
{
if ((*i)->type_ == 1)
total += ((A*)(*i))->f();
else
total += ((B*)(*i))->f();
}
double twe = tw.elapsed();
std::cout << "switched: " << total << ' ' << twe << '\n';
// ----------------------------
total = 0;
Timer tw2;
for (int i = 0; i < 100000; ++i)
for (W::const_iterator i = w.begin(); i != w.end(); ++i)
total += (*i)->type_;
double tw2e = tw2.elapsed();
std::cout << "overheads: " << total << ' ' << tw2e << '\n';
}
}
性能結果
在我的Linux系統:
~/dev g++ -O2 -o vdt vdt.cc -lrt
~/dev ./vdt
virtual dispatch: 150000000 1.28025
switched: 150000000 0.344314
overhead: 150000000 0.229018
virtual dispatch: 150000000 1.285
switched: 150000000 0.345367
overhead: 150000000 0.231051
virtual dispatch: 150000000 1.28969
switched: 150000000 0.345876
overhead: 150000000 0.230726
這表明聯機型號碼切換方法的速度約爲(1.28 - 0.23)/(0.344 - 0.23)= 9.2倍。當然,這隻針對確切的系統測試/編譯器標誌&版本等,但通常是指示性的。
評論RE虛擬監控調度
必須說,雖然虛擬函數調用的開銷是東西是很少顯著,並且只適用於經常被稱爲瑣碎的功能(如getter和setter)。即使那樣,你也許可以提供一個功能來同時獲取和設置很多東西,從而最大限度地降低成本。人們擔心虛擬調度的方式太多 - 所以在找到彆扭的方案之前也要進行剖析。它們的主要問題是它們執行一個外聯函數調用,儘管它們也會移除執行的代碼,這會改變緩存利用率模式(爲了更好或更常見)。
使用多態類實現它。調度虛擬功能的開銷很可能是微不足道的。最糟糕的情況是,這很重要,而且你至少會有一個乾淨的設計,可以相對容易地進行優化。 – 2011-01-26 06:25:56