首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >什么是面向数据的设计?

什么是面向数据的设计?
EN

Stack Overflow用户
提问于 2009-10-29 12:13:33
回答 4查看 86.1K关注 0票数 185

我正在阅读this article,这个人继续谈论如何每个人都可以从面向数据的设计和OOP的混合中获得巨大的好处。然而,他没有展示任何代码样本。

我在谷歌上搜索了一下,找不到任何关于这是什么的真实信息,更不用说任何代码样本了。有没有人熟悉这个术语并能提供一个例子?这是不是其他东西的另一个词呢?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-01-08 00:29:54

首先,不要将这与数据驱动设计混淆。

我对面向数据的设计的理解是,它是关于组织数据以进行有效处理的。特别是在缓存未命中等方面。另一方面,数据驱动设计是关于让数据控制程序的许多行为(Andrew Keith's answer对此进行了很好的描述)。

假设您的应用程序中有一些球对象,这些对象具有诸如颜色、半径、弹力度、位置等属性。

面向对象的方法

在OOP中,你可以这样描述球:

代码语言:javascript
复制
class Ball {
    Point  position;
    Color  color;
    double radius;

    void draw();
};

然后创建一个球的集合,如下所示:

代码语言:javascript
复制
vector<Ball> balls;

面向数据的方法

然而,在面向数据的设计中,您更有可能像这样编写代码:

代码语言:javascript
复制
class Balls {
    vector<Point>  position;
    vector<Color>  color;
    vector<double> radius;

    void draw();
};

正如你所看到的,不再有单个单位代表一个球了。球对象只隐式存在。

这在性能方面有很多优势。通常,我们希望同时对多个球进行操作。硬件通常需要大量连续的内存块才能有效地运行。

其次,您可以执行仅影响球的部分属性的操作。例如,如果你以各种方式组合所有球的颜色,那么你希望你的缓存只包含颜色信息。但是,当所有球的属性都存储在一个单元中时,您将同时引入球的所有其他属性。即使你不需要它们。

缓存使用示例

假设每个球占用64个字节,一个点占用4个字节。比方说,一个缓存槽也占用64字节。如果我想更新10个球的位置,我必须将10x64= 640字节的内存放入缓存中,并获得10个缓存未命中。但是,如果我可以将球的位置作为单独的单元来计算,那么只需要4x10= 40个字节。这适用于一次高速缓存获取。因此,我们只有一次缓存未命中来更新所有10个球。这些数字是任意的-我假设缓存块更大。

但它说明了内存布局如何对缓存命中产生严重影响,从而影响性能。这只会随着CPU和RAM速度之间的差异扩大而变得更加重要。

如何布局内存

在我的ball示例中,我大大简化了问题,因为通常对于任何普通的应用程序,您可能会一起访问多个变量。例如,位置和半径可能会经常一起使用。那么你的结构应该是:

代码语言:javascript
复制
class Body {
    Point  position;
    double radius;
};

class Balls {
    vector<Body>  bodies;
    vector<Color>  color;

    void draw();
};

您应该这样做的原因是,如果一起使用的数据放在不同的阵列中,则它们会竞争缓存中的相同插槽。因此,加载一个会抛出另一个。

因此,与面向对象编程相比,您最终创建的类与您的问题心理模型中的实体无关。由于数据是根据数据使用情况组合在一起的,因此在面向数据的设计中,您并不总是有合理的名称来命名您的类。

与关系数据库的关系

面向数据的设计背后的思想与您对关系数据库的思考非常相似。优化关系数据库还可以涉及更有效地使用缓存,尽管在这种情况下,缓存不是CPU缓存,而是内存中的页。一个好的数据库设计人员可能还会将不经常访问的数据拆分到一个单独的表中,而不是创建一个包含大量列的表,其中只使用其中的几列。他可能还会选择对一些表进行反规范化,这样就不必从磁盘上的多个位置访问数据。就像面向数据的设计一样,这些选择是通过查看数据访问模式是什么以及性能瓶颈在哪里来做出的。

票数 344
EN

Stack Overflow用户

发布于 2010-02-23 10:03:36

我只想指出,Noel专门谈到了我们在游戏开发中面临的一些具体需求。我认为正在进行实时软模拟的其他部门将从中受益,但它不太可能是一种对一般业务应用程序显示出显著改进的技术。这种设置是为了确保从底层硬件中挤出最后一点性能。

票数 15
EN

Stack Overflow用户

发布于 2021-01-03 03:06:05

如果你想利用现代处理器架构,你需要以某种方式在内存中布局你的数据。CPU非常擅长处理在内存中按顺序排列的简单类型。任何其他布局的处理成本都要高得多。

在面向对象的方法中,您总是考虑一个实例,然后通过将对象分组为集合来将其扩展到多个实例。但从硬件的角度来看,这会带来额外的成本。

在面向数据的方法中,您没有像在面向对象编程中那样的“实例”。您的实例可以有一个标识符,类似于关系数据库中的数据,但除此之外,与您的实例相关的数据可以拆分到几个表中(表以向量的形式实现),以实现高效的处理。

例如:假设您有类Student { int id;std::string name;float average;bool graduated;}。在OOP的情况下,你会把你所有的学生放在一个单独的向量中。

在面向数据的设计中,您首先会问自己想要对这些数据进行什么样的处理。假设你想为所有还没有毕业的学生计算一个平均分。因此,您将创建一个表,其中只包含已毕业的学生和另一个未毕业的学生。您不会将学生姓名保留在该表中,因为它不用于处理。但您将在表中保留一个学生号和一个平均分。

现在计算未毕业学生的平均分数将意味着迭代未毕业学生表并执行计算。由于平均标记在内存中是相邻的,因此您的CPU将使用SIMD并以最有效的方式处理数据。由于我们不会查询布尔毕业生来测试该学生是否已毕业,因此没有数据缓存未命中。

理论上这听起来不错,但我从来没有在现实世界的项目中做过这样的开发。如果任何人有任何经验,请与我联系,我有很多问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1641580

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档