目录
2.测试用例2-我的测试结果与原作者的测试结果不太一样,at的性能没差那么多
0.引入与一些阅读链接
虚函数慢的原因主要有三个:
(1)多了几条汇编指令(实际上多了三条汇编指令:取虚表,取函数地址,call调用)
(2)影响cpu流水线
(3)编译器不能内联优化(因为在得到子类的引用或者指针之前,根本不知道要调用哪一个函数,所以无从内联,
仅在用父类引用或者指针调用时,不能内联;要注意的是,对于子类直接调用虚函数,是可以内联优化的)
测试结论(基于文章《虚函数到底有多慢》这个链接的结论):
(1)虚函数调用效率和继承层数无关;
(2)其实虚函数还是挺快的。
(3)如果真的要完全移除虚函数,那么如果要实现运行时多态,则要用到函数指针,据上面的分析,函数指针基
本具有虚函数的所有缼点(要传递函数指针,同样无法内联,同样影响流水线),且函数指针会使代码混乱。
1.测试用例1
编译选项:g++ VirtualFunc.cpp -std=c++11 -O2
执行:./a.out
视频UP主强调的是CPU的分支预测给虚函数带来了一定的性能消耗,如果能够对其排序,则会一定程度上
大幅度缓解这种性能消耗.
#include <iostream>
#include <vector>
#include <algorithm>
#include <chrono>
using timer=std::chrono::high_resolution_clock::time_point;
struct A
{
virtual int foo()
{
return i;
}
int i;
};
struct B:public A
{
virtual int foo() override
{
return A::i + 1;
}
};
std::vector<A*> gen_data(int N)
{
std::vector<A*> va;
for(int i = 0;i<N;i++)
{
if(rand()&1)
{
va.push_back(new A());
}
else
{
va.push_back(new B());
}
va.back()->i = rand();
}
std::random_shuffle(va.begin(),va.end());
return va;
}
int test(int M,const std::vector<A*> &va)
{
timer start = std::chrono::high_resolution_clock::now();
int sum = 0;
for(int i =0;i<M;i++)
{
for(size_t j = 0;j<va.size();j++)
{
sum +=va[j]->foo();
}
}
timer end = std::chrono::high_resolution_clock::now();
std::cout <<"line = "<<__LINE__<< ", eclipsed milliseconds:"<<std::chrono::duration_cast<std::chrono::milliseconds> (end-start).count()<<std::endl;
return sum;
}
int main(){
srand(12345);
const int N = 10000;
std::vector<A*> va=gen_data(N);
const int M = 10000;
int sum = test(M,va);
std::cout << "sum = " << sum << std::endl;
std::sort(va.begin(),va.end(),[](const A* a,const A* b){return typeid(*a).before(typeid(*b));});
sum = 0;
sum = test(M,va);
std::cout << "sum = " << sum << std::endl;
return 0;
}
2.测试用例2-我的测试结果与原作者的测试结果不太一样,at的性能没差那么多
#include <iostream>
#include <time.h>
#include <vector>
using namespace std;
const int size = 100000000;
class Vector{
private:
int *array;
int pos;
public:
Vector(int size):array(new int[size]),pos(0)
{
}
void push_back(int val)
{
array[pos++] = val;
}
int at(int i)
{
return array[i];
}
void clear()
{
pos = 0;
}
};
class IVector{
public:
virtual void push_back(int val) = 0;
virtual int at(int i) = 0;
virtual void clear() = 0;
virtual ~IVector() {};
};
class VirtualVector : public IVector{
public:
int *array;
int pos;
public:
VirtualVector(int size):array(new int[size]),pos(0)
{
}
void push_back(int val)
{
array[pos++] = val;
}
int at(int i)
{
return array[i];
}
void clear()
{
pos = 0;
}
~VirtualVector()
{
if(array != NULL)
delete array;
}
};
void testVectorPush(Vector& v){
v.clear();
clock_t nTimeStart; //计时开始
clock_t nTimeStop; //计时结束
nTimeStart = clock(); //
for(int i = 0; i < size; ++i)
{
v.push_back(i);
//cout<<v.size()<<endl;
}
nTimeStop = clock(); //
cout <<"耗时:"<<(double)(nTimeStop - nTimeStart)/CLOCKS_PER_SEC<<"秒"<< endl;
}
void testVectorAt(Vector& v)
{
clock_t nTimeStart; //计时开始
clock_t nTimeStop; //计时结束
int sum = 0;
nTimeStart = clock(); //
for(int j = 0; j < 1; ++j)
{
for(int i = 0; i < size; ++i)
{
sum += v.at(i);
}
}
nTimeStop = clock(); //
cout <<"耗时:"<<(double)(nTimeStop - nTimeStart)/CLOCKS_PER_SEC<<"秒,";
cout<<"sum:"<<sum<<endl;
}
void testVirtualVectorPush(IVector& v)
{
v.clear();
clock_t nTimeStart; //计时开始
clock_t nTimeStop; //计时结束
nTimeStart = clock(); //
for(int i = 0; i < size; ++i)
{
v.push_back(i);
//cout<<v.size()<<endl;
}
nTimeStop = clock(); //
cout <<"耗时:"<<(double)(nTimeStop - nTimeStart)/CLOCKS_PER_SEC<<"秒"<< endl;
}
void testVirtualVectorAt(IVector& v)
{
clock_t nTimeStart; //计时开始
clock_t nTimeStop; //计时结束
int sum = 0;
nTimeStart = clock(); //
for(int j = 0; j < 1; ++j)
{
for(int i = 0; i < size; ++i)
{
sum += v.at(i);
}
}
nTimeStop = clock(); //
cout <<"耗时:"<<(double)(nTimeStop - nTimeStart)/CLOCKS_PER_SEC<<"秒,";
cout<<"sum:"<<sum<<endl;
}
int main()
{
//cout<<sizeof(VirtualVector)<<endl;
Vector *v = new Vector(size);
VirtualVector *V = new VirtualVector(size);
cout<<"====================================================testVectorPush===================================="<<endl;
testVectorPush(*v);
testVectorPush(*v);
testVectorPush(*v);
testVectorPush(*v);
cout<<"====================================================testVirtualVectorPush============================="<<endl;
testVirtualVectorPush(*V);
testVirtualVectorPush(*V);
testVirtualVectorPush(*V);
testVirtualVectorPush(*V);
cout<<"====================================================testVectorAt======================================"<<endl;
testVectorAt(*v);
testVectorAt(*v);
testVectorAt(*v);
testVectorAt(*v);
cout<<"====================================================testVirtualVectorAt==============================="<<endl;
testVirtualVectorAt(*V);
testVirtualVectorAt(*V);
testVirtualVectorAt(*V);
testVirtualVectorAt(*V);
return 0;
}