> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/jia-gou/data-oriented-programming.md).

# 数据导向编程

数据导向编程是一种强大的编程方法，能最大程度发挥性能。

面向数据编程是一种强大的编程方法，能显著提升性能。它着重于将 *数据* 作为核心元素，其他一切都围绕它组织，以便访问或修改这些数据。这种方法也非常适合多人模式，因为它让玩家之间需要同步的数据更容易、更快地访问。

面向数据编程鼓励你把场景中的一切都看作需要在各个系统之间被复制和变异的数据。这种方法的主要好处在于优化数据从内存中读取的速度，而这通常是运行现代应用和游戏时的主要瓶颈。

正因为性能有了如此显著的提升，过去几年里，游戏制作行业中的很大一部分都在转向采用这种方法。

Decentraland 的 SDK 用 JavaScript 执行场景，而这种语言的一个缺点是无法控制内存分配。不过，运行 Decentraland 的引擎使用的是 C#，而遵循面向数据原则对它有很大好处。SDK 和引擎会不断地相互发送消息。为了让这种通信尽可能高效，最好让双方的数据结构尽可能相似，以避免不得不频繁重组这些数据。

## 它的样子

面向数据编程不同于面向对象编程，后者是许多开发者目前都熟悉的方法。在面向对象编程中，代码是按照试图复刻现实世界构造的抽象来组织的：对象。这些对象中的每一个都可以同时持有数据和功能。采用这种方法的应用通常在概念上很容易规划，但运行效率也更低。

在面向数据编程中，数据并不是围绕对象来组织的，而是围绕优化访问便捷性来组织。数据所代表的现实世界构造，并不会参与到修改这些数据的不同流程中。

Decentraland SDK 所基于的实体组件系统（ECS）模型，与面向数据编程方法非常兼容。每个组件都是结构化数据集合的一部分。组件通过引用属于某个实体，但数据并不是围绕实体来组织的，数据是作为一组相似组件来组织的。例如，场景中的所有 `Transform` 组件都是平等的。其中一个变换可能属于你主建筑的模型，另一个可能属于桌子上的一块玻璃。然后场景中的系统会逐个处理 `Transform` 组件，而不会做任何区分。所有 `Transform` 组件都具有相同的字段，并接受相同的检查。

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-2f8795b95cc1b4e9f2a9e37cdb54e9841d123b46%2Fcomponent-stacks.png?alt=media)

想象一个场景里有十几扇门，它们要么是打开的，要么是关闭的。你可以把这些门的状态表示为一个简单的“isOpen”组件，其中保存一个布尔值。如果“isOpen”为 true，门就应该是打开的；如果为 false，门就应该是关闭的。如果玩家点击一扇门，它应该切换状态，其他玩家也应该看到它发生切换。当你的场景正在处理某扇门状态的变化，并与其他玩家同步时，场景其实并不关心“isOpen”代表什么。整组组件不过是一些需要与其他玩家同步的布尔值集合。场景中的另一个系统随后可以负责定期将每个“isOpen”的状态与对应门的旋转保持一致。

面向数据编程并不一定更难，但它是一种需要学习和采用的不同方法。那些不习惯这种方法的开发者可能需要一些时间来熟悉它，我们鼓励你去探索并尝试这些示例，以更好地形成感觉。

## 为什么它有效

要理解为什么面向数据编程会带来如此大的差异，我们需要看看硬件。

当处理器需要从内存中获取数据时，它会把一整块数据读入缓存，其中也包括那些恰好写在我们想要的值旁边的内存数据。你的代码越能利用已经在缓存中的数据，运行速度就越快。

想象机器的内存是一座真实的仓库，数据被存放在许多堆叠的箱子里。每当我们需要某一小部分数据时，就得叫来一辆叉车，去取出装有那部分数据的箱子，并把它送到前台检查。前台一次只能放下几个箱子，所以你不能保留太多数据。

叉车要跑到仓库后面把箱子给我们取回来，需要很长时间。如果你想要的这些箱子里的数据是分散的，那就意味着要让叉车来回跑很多趟。大多数时候，你会站在前台旁干等着，等你请求的下一个箱子到来。

如果你能聪明地堆放这些箱子，并把那些你很可能会同时需要的数据尽量归在一起，就能避免很多浪费的时间。巧妙地分组数据后，你通常会发现你接下来需要的东西已经在前台的某个箱子里了。你可以直接开始使用，而不用麻烦叉车操作员。

例如，如果你的场景需要获取一扇门的状态来检查它是打开还是关闭，硬件读取的就不只是描述这扇门状态的那个布尔值本身，还会读取许多其他可能相关或不相关的数据。

假设你的场景里有一个系统，需要每一帧更新十二扇门的开/关状态。如果你的代码是按照面向对象编程方式组织的，就无法知道不同相关信息会如何被分组。也许我们仓库里的某个“箱子”同时装着门 A 的“isOpen”状态、门 A 的纹理，以及它在打开时播放的音频。你可能得为这十二扇门中的每一扇都跑一趟，去获取一个新的数据“箱子”。当然，这整个过程需要在每一帧都再次发生。所以即使这些门都没有改变状态，每秒也相当于要进行 360 次（30 × 12）比喻性的仓库后部往返。

另一方面，如果你的代码遵循面向数据的方法，那么这 12 个布尔值很可能都在同一个箱子里。这是因为这些布尔值都属于一个一次性写入内存的单一数组。你并不会显式地组织这些数据如何适配内存，所以在最坏的情况下，数组可能会被分成两个箱子。不过即使是在这种最坏的情况下，2 次往返也比 12 次好得多。

在每一帧检查每扇门的状态听起来像是很多工作，但如果所有数据都已经在内存缓存中，那其实非常快。如果你的数据组织得井井有条，你的场景就可以在大量实体上运行这类流程，同时仍然保持非常快的速度。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/jia-gou/data-oriented-programming.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
