问题标签 [data-oriented-design]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - 使用函数指针切割 if 语句会更有效吗?
因此,有这条规则可以尝试将if
语句从高重复循环中拉出来:
他们说,最好将其分解,将 if 语句放在外面:
(如果您说“哦!不要自己优化!编译器会这样做!”)当然优化器可能会为您执行此操作。但是在典型的 C++ 废话中(我不同意他的所有观点,例如他对虚函数的态度)Mike Acton 说:“为什么要让编译器猜测你知道的东西?对我来说,这几乎是这些粘性的最佳点。
那么为什么不使用函数指针呢?
函数指针是否存在某种隐藏开销?调用直接函数是否有效?
c++ - OOP 中的面向数据设计
在这张幻灯片 中(在幻灯片 15 之后),建议使用
因为它的缓存效率更高。
如果我有课怎么办
我将该类的所有对象存储在一个线性数组中。
由于它们都在同一个数组中,会有缓存未命中吗?为什么第一种方法会更好?
performance - 面向对象、面向数据、缓存污染和缓存明显性
在常规的面向对象实践中,很少有对象具有多个不相关的成员属性。并且在处理对象时,在不同的通道中完成并针对其属性的不同部分进行处理的情况并不少见。
在这方面,创建对象集合的典型方法似乎不是一种非常有效的方法。考虑到计算机访问内存的方式和高速缓存行的平均大小,高速缓存很有可能被不需要的内存填满,而只是碰巧相邻,因此最终浪费了缓存的容量并增加了停顿和执行延迟。
更糟糕的是使用多态性和动态分配对象的做法,没有内存池和自定义分配器。在这种情况下,不仅高速缓存充满了不需要的数据,而且由于动态内存分配使用的任意地址,预取器也无法充分工作。
拯救是回到 OOP 之前的时代并选择面向数据,这似乎是开发性能关键应用程序、操作系统等的偏好选择。但是为什么不使用两者的混合版本呢?面向数据的对象编程排序?
经过这么长的序曲,让我们来看看手头的问题。我没有足够庞大的项目来测试这个概念的效率,因此非常欢迎社区的理论专业知识。
如果对象不存储自己的数据成员,它们只存储对集合的引用,它们的数据成员按顺序存储在自己的容器中,并且它们的成员方法从这些容器返回数据,这样不需要的数据结束的几率应该减少到 CPU 的路上,并且增加在不久的“未来”需要的数据的几率。合乎逻辑的假设是,这种方法将提高预取器效率、缓存命中率和使用效率,还将减少自动和手动并行化所涉及的延迟。
你怎么看?
后期编辑:如果我们考虑结构和类填充,则应用“数据定向模式”可能会更有益,如果“模型”具有 achar
和 aint
数据成员,则在 OOP 方式中它将被填充,这只会造成污染进一步缓存,但是面向数据的存储模式可以将所有char
s和所有int
s顺序存储,完全没有空间和缓存浪费。
data-oriented-design - 如何处理连续分配中的对象删除?
我最近发现了面向数据设计的好处。它看起来非常令人印象深刻。要点之一是按类型和访问对数据进行分组,而不是全部放在对象中,而是放在数组中,以防止缓存未命中并进行更好的处理。
所以在游戏中我们仍然有实例并且用户可以销毁它们中的任何一个(不仅仅是最后一个数组)。我不知道如何有效地处理数组中间的对象删除。
我有一个想法:isAlive
有价值,但这会对条件数量造成相当大的影响,因为每个对象在处理,绘图,...
另一个想法是移动整个数组以填充必须删除的空间,但这会在删除时消耗大量资源。
人如何在国防部处理这个问题?
所以提出要求:
- 它必须是数组以减少 DOD 中的缓存未命中
- 它必须有快速的随机位置对象删除,最大 o(log n)
- 对象自创建以来就不能移动,因为它们可能在未知的地方被引用,因此会导致程序异常
c++ - 对多个索引数据数组的面向数据的访问
我正在为游戏引擎开发实体组件系统。我的目标之一是使用面向数据的方法来优化数据处理。换句话说,我想遵循宁愿需要数组结构而不是结构数组的准则。但是,我的问题是我还没有找到一种巧妙的方法来为我解决这个问题。
到目前为止,我的想法是系统中的每个组件都负责游戏逻辑的特定部分,比如重力组件负责根据质量、速度等计算每一帧的力,而其他组件负责其他事情。因此,每个组件都对不同的数据集感兴趣。重力组件可能对质量和速度感兴趣,而碰撞组件可能对边界框和位置等感兴趣。
到目前为止,我认为我可以拥有一个数据管理器,它可以为每个属性保存一个数组。假设实体可能具有重量、位置、速度等中的一项或多项,并且它们将具有唯一的 ID。数据管理器中的数据将表示如下,其中每个数字代表一个实体 ID:
如果所有实体都具有每个属性,则此方法效果很好。但是,如果只有实体 0 和 2 具有所有树属性,而其他实体是不移动类型的实体,它们将没有速度,数据将如下所示:
突然间,迭代它并不容易。如果我采用第二种方法,一个只对迭代和操纵速度感兴趣的组件将不得不以某种方式跳过空白间隙。保持数组短的第一种方法在更复杂的情况下也不能很好地工作。假设我有一个具有所有三个属性的实体 0,另一个只有重量和位置的实体 1,以及只有位置和速度的实体 2。最后,最后一个实体 3 只有权重。被压扁的数组看起来像:
另一种方法会留下如下空白:
如果您只对迭代只有少数属性的实体集感兴趣,那么这两种情况都不是简单的迭代。例如,给定的组件 X 会对处理具有位置和速度的实体感兴趣。如何提取可迭代数组指针以提供给该组件进行计算?我想给它一个数组,其中元素彼此相邻,但这似乎是不可能的。
我一直在考虑解决方案,例如为每个数组设置一个位字段,描述哪些点是有效的,哪些是间隙,或者一个系统将数据复制到没有孔的临时数组,然后将其提供给组件,以及其他想法,但我认为没有一个是优雅的,并且没有额外的处理开销(例如额外检查数据是否有效,或额外复制数据)。
我在这里问是因为我希望你们中的某些人可能有类似的经验,或者可能有有助于解决这个问题的想法或想法。:) 此外,如果这整个想法是废话并且不可能正确,而您有一个更好的想法,请告诉我。希望这个问题不会太长或太混乱。
谢谢。
c++ - 如何在 DOD 之后创建多层感知器?或者如何存储动态分配的数组?
首先,我对 DOD 的这个概念很陌生,虽然对它很陌生,但从程序员的角度来看,我发现它真的很令人兴奋。
不久前,我为自己制作了一个多层感知器作为 OO 项目,并且由于我现在正在学习 DOD,所以我认为使用这种范例来制作它会很好。
我知道它可能不是(而且几乎肯定不是)最好的格式,但我试图将我在不同图层数组中使用得更多的东西分开。但是数组的存储方式确实让我很感兴趣,因为它们应该作为一个结构堆叠在一起,以便更快地读取内存(或者我错过了什么?)。如果我没记错的话, new[] 将数组分配在内存中的某个位置,并且只存储指向该位置的指针,而结构中的静态数组将在其空间内分配。
基于此,我想到了制作层(和网络)模板结构:
但是,如果 Layer 变成了这样的东西,是否有任何方法可以制作具有任意数量隐藏层的 Network 可变参数模板?还是我对静态数组的理解是错误的?创建此类数组(和访问时间)之间有什么区别吗?我的钥匙在哪里?
c++ - 哪个对缓存最友好?
我试图很好地掌握面向数据的设计以及如何在考虑缓存的情况下进行最佳编程。基本上有两种情况,我无法完全确定哪个更好,为什么 - 拥有一个对象向量还是多个具有对象原子数据的向量更好?
A) 对象向量示例
B) 带有原子数据的向量
哪一个内存效率更高且缓存更友好,从而导致更少的缓存未命中和更好的性能,为什么?
c++ - 了解缓存友好、面向数据的对象和句柄
考虑一种传统的OOP 方法来进行实体/对象管理:
但是,我想尝试一种面向数据的方法:不是动态分配Entity
实例,而是将它们存储在缓存友好的线性内存中。
看起来很好。但是……如果std::vector
需要重新分配其内部数组,所有对实体的引用都将变得无效。
解决方案是使用句柄类。
如果我只是在向量后面添加/删除实体,它似乎可以工作。我可以使用getEntity
方法来检索我想要的实体。
但是如果我Entity
从向量的中间移除一个呢?所有EntityHandle
实例现在都将持有不正确的索引,因为一切都被转移了。例子:
句柄指向索引:2
实体 A 在 update() 期间被删除
现在句柄指向错误的实体。
这个问题一般是怎么处理的?
句柄索引是否更新?
死实体是否被占位符替换?
澄清:
此外,诸如Artemis之类的组件系统声称采用线性缓存友好设计,并且它们使用类似于句柄的解决方案。他们如何处理我在这个问题中描述的问题?
c - If 语句与函数指针
目标是改变事件循环中的行为,具体取决于复选框是打开还是关闭。我能想到的最简单的方法就是在每次运行循环时测试复选框状态。
如果使用函数指针,代码会更高效、更简洁还是以其他方式更好?像这样:
c++ - 类型应该在面向数据的设计中有方法吗?
目前,我的应用程序包含三种类型的类。它应该遵循面向数据的设计,如果不是,请纠正我。这是三种类型的类。代码示例并不那么重要,您可以根据需要跳过它们。他们只是在那里给人留下印象。我的问题是,我应该向我的类型类添加方法吗?
当前设计
类型只是保存值。
每个模块实现一个独特的功能。他们可以访问所有类型,因为它们是全局存储的。
管理Module
器是一种通过基类注入模块的助手。上面用到Entity
的是一个实体管理器的实例。其他管理器涵盖消息传递、文件访问、sql 存储等。简而言之,应该在模块之间共享的每个功能。
有问题
现在你已经了解了我目前的设计。现在考虑一个类型需要更复杂的初始化的情况。例如,该Model
类型刚刚为其纹理和顶点缓冲区存储了 OpenGL id。实际数据必须先上传到显卡。
目前,有一个Models
具有功能的模块Create()
,负责设置模型。但是这样,我只能从这个模块创建模型,而不能从其他模块创建。Model
我应该在复杂化的同时将其移至类型类吗?我之前认为类型定义只是一个接口。