" 缓存不友好代码 "和" 缓存友好 "代码之间有什么区别?
如何确保编写高效缓存代码?
在C++中使用接口(抽象基类)时是否存在运行时性能损失?
在我用C++编写的AI应用程序中,
在这种情况下,有没有任何优化技术?虽然我现在不打算优化应用程序,但为项目选择C++而不是Java的一个方面是提供更多的优势,以便能够使用非面向对象的方法(模板,过程,重载).
特别是,与虚拟功能相关的优化技术是什么?虚函数通过内存中的虚拟表实现.有没有办法将这些虚拟表预取到L2缓存上(从内存/ L2缓存中获取的成本正在增加)?
除此之外,C++中的数据局部技术是否有很好的参考?这些技术将减少数据提取到计算所需的L2高速缓存的等待时间.
我有兴趣知道是否有任何可行的方法来连续存储多态对象数组,这样virtual可以合法地调用公共基础上的方法(并将调度到子类中正确的重写方法).
例如,考虑以下类:
struct B {
int common;
int getCommon() { return common; }
virtual int getVirtual() const = 0;
}
struct D1 : B {
virtual int getVirtual final const { return 5 };
}
struct D2 : B {
int d2int;
virtual int getVirtual final const { return d2int };
}
Run Code Online (Sandbox Code Playgroud)
我想分配一个连续的D1和D2对象数组,并将它们视为B对象,包括调用getVirtual()哪些将根据对象类型委托给适当的方法.从概念上讲,这似乎是可能的:每个对象通常通过嵌入的vtable指针知道它的类型,因此您可以想象,将n个对象存储在数组中,并使用放置和初始化对象,并将指针转换为.不过,我很确定演员不合法.n * max(sizeof(D1), sizeof(D2)) unsigned charnewdeleteunsigned charB*
人们还可以想象创建一个联盟,如:
union Both { …Run Code Online (Sandbox Code Playgroud) 因此,假设我想创建一系列类,每个类都具有相同的成员函数.我们来调用这个函数吧
void doYourJob();
Run Code Online (Sandbox Code Playgroud)
我想最终把所有这些类放到同一个容器中,这样我就可以遍历它们并让每个类都执行'doYourJob()'
显而易见的解决方案是使用该函数创建一个抽象类
virtual void doYourJob();
Run Code Online (Sandbox Code Playgroud)
但我这样做犹豫不决.这是一个耗时的计划,虚拟功能可以大大提高它.此外,这个函数是类中唯一相互共同的函数,并且doYourJob对每个类的完全不同.
有没有办法避免使用具有虚函数的抽象类,或者我将不得不吮吸它?
我刚从@ tony-d 找到了这个答案,用一个基准代码来测试虚函数调用开销.我查了基准使用g++:
$ g++ -O2 -o vdt vdt.cpp -lrt
$ ./vdt
virtual dispatch: 150000000 0.128562
switched: 150000000 0.0803207
overheads: 150000000 0.0543323
...
Run Code Online (Sandbox Code Playgroud)
我的表现更好(他的比例约为2),但后来我查了一下clang:
$ clang++-3.7 -O2 -o vdt vdt.cpp -lrt
$ ./vdt
virtual dispatch: 150000000 0.462368
switched: 150000000 0.0569544
overheads: 150000000 0.0509332
...
Run Code Online (Sandbox Code Playgroud)
现在这个比例上升到70左右!
然后我注意到了-lrt命令行参数,经过一些谷歌搜索后,librt我尝试了没有它g++和clang:
$ g++ -O2 -o vdt vdt.cpp
$ ./vdt
virtual dispatch: 150000000 0.4661
switched: 150000000 0.0815865
overheads: 150000000 0.0543611
...
$ …Run Code Online (Sandbox Code Playgroud) 出于性能原因,我使用Curiously Reoccuring模板模式来避免虚函数.我有很多执行数百万次的小命令.我试图将其纳入命令模式.我想在队列中添加大量命令,然后迭代执行每个命令.每个命令使用CRTP来避免虚函数.我遇到的问题是Command模式通常使用指针向量来实现.但是当Command类被模板化时,很难传递通用的Command指针.我不是C++专家,所以也许有一种显而易见的方法来存储模板化命令对象的向量?我一直试图使用类似的东西:
boost:ptr_vector commands;
AddCommand(Command* command) {
commands.push_back(command);
}
Run Code Online (Sandbox Code Playgroud)
问题是Command不是类型,因此Command* command给出了编译错误.我需要使用Command<CommandType>,但这不起作用,因为我需要队列来保存不同类型的命令.
任何解决方案的想法?或者虚拟功能是我唯一的选择吗?
增加:命令对象是蒙特卡罗模拟算法的一部分.所以你可能有,Command是来自正态分布的随机数,其中正态分布的参数是类的一部分.所以命令模式非常合适.我按特定顺序对需要维护状态的函数进行了大量调用.
我正在努力尝试使用枚举和大量的宏观魔法来实现vtable的替代品,这种魔法真的开始让我的大脑混乱.我开始认为我没有走正确的道路,因为代码变得更加丑陋和丑陋,并且无论如何都不适合生产.
如何使用最少量的重定向/操作实现以下代码的模式?
它必须在标准的c ++中完成,最多17个.
class A{
virtual void Update() = 0; // A is so pure *¬*
};
class B: public A
{
override void Update() final
{
// DO B STUFF
}
}
class C: public A
{
override void Update() final
{
// DO C STUFF
}
}
// class...
int main()
{
std::vector<A*> vecA{};
// Insert instances of B, C, ..., into vecA
for(auto a: vecA) // This for will be inside a main loop
a->Update(); // …Run Code Online (Sandbox Code Playgroud) 我有个问题.我正在尝试创建代码来更新我的游戏,但我陷入了"两难".我不想使用虚拟和它的唯一原因是我在谈论的每个人(在论坛,聊天,朋友)说虚拟使代码真的很慢,所以我做了一个研究,发现它做的查找vtable可以将性能降低近一半.因此,我将它用于不需要每帧更新的任务.一切正常,直到我得到更新/渲染功能.然后我开始考虑寻找解决方法.有了一个想法,但首先我想问一下那些知道那个人的人在实施之前.
我的游戏引擎非常受事件驱动.我可以使用子系统之间的事件(图形,UI,脚本)发送任何类型的数据.所以,我正在考虑每帧发送一个事件"renderScene".这对我来说听起来不错,但是有一个问题.事件处理程序的结构并不是很好,我现在真的不想改进它,因为它做得非常不错,我的目标是完成我的游戏,而不是修理引擎而永远不会完成它(碰巧我,所以不想再回到它了.
我的事件处理程序有一个函数将事件注册到函数(我称之为处理程序).但是这个函数的问题是,我需要做函数绑定和东西来注册成员函数.所以,我找到了一个解决方法 - 我创建一个静态函数并从中调用成员函数.这就是静态函数的样子:
void GraphicsSubsystem::renderScene(Subsystem * subsystem, Event * event) {
GraphicsSubsystem * graphics = static_cast<GraphicsSubsystem *>(subsystem);
graphics->renderScene();
}
void ScriptingSubsystem::runLine(Subsystem * subsystem, Event * event) {
ScriptingSubsystem * scripting = static_cast<ScriptingSubsystem *>(subsystem);
Event1<String> * e = static_cast<Event1<String> *>(event);
scripting->runLine(e->getArg());
}
Run Code Online (Sandbox Code Playgroud)
参数始终是抽象子系统类和基本事件类.该runLine功能我没有问题,因为铸造我不运行的每个机架上的一行代码.但是,renderScene函数让我有点不舒服.
tl;博士,这是我的问题.静态构建每个帧上的对象比在每个帧上调用虚函数更快吗?
我有一个抽象类,例如Animal。Animal 有一个纯虚函数eat,如果每个动物不想挨饿,就必须实现它。我确保只能通过这种方式实例化 Animal 的孩子:
动物.hpp
class Animal
{
public:
enum eAnimal{
CAT=0,
DOG=1,
BIRD=2
};
// Instantiates the desired animal.
static Animal GetAnimal(const int animal);
virtual void Eat() const = 0;
protected:
Animal();
};
Run Code Online (Sandbox Code Playgroud)
动物.cpp
Animal Animal::GetAnimal(const int animal)
{
switch(animal)
{
case CAT:
return Cat();
case DOG:
return Dog();
case BIRD:
return Bird();
default:
cerr << "Animal not recognized." << endl;
exit(-1);
}
}
Animal::Animal()
{}
Run Code Online (Sandbox Code Playgroud)
有了这个,猫将是:
猫.hpp
class Cat : public Animal …Run Code Online (Sandbox Code Playgroud) c++ ×10
performance ×3
polymorphism ×3
benchmarking ×1
caching ×1
casting ×1
cpu-cache ×1
dispatch ×1
enums ×1
librt ×1
memory ×1
optimization ×1
templates ×1