目录:
前文中说过,ECS的核心就是多线程并发与紧凑化数据处理。这一部分先从后者开始谈起,第一是更简单,第二是多线程并不一定需要使用,但内存一定要时刻注意,单线程也可以面向数据编程,而高效的数据存储方式决定了大规模数据处理的效率高低,哪怕不引入多线程也可以有明显提升。
ECS(Entity+Component+System)
回顾一下:Entity即实体,Component装载组件数据,System则是代码算法;ECS可以将数据与行为分离,让数据紧密排列,减少内存碎片的产生(更高效化利用内存)
Entity是实体,可以理解为Dots中的GameObject。但与GO不同的是,并且Entity实际上只是一个ID,它不包含代码,只包含其所属的Components。但在Hierarchy中,Entity仍表现的像一个GO,Inspector也像,并且拥有基础的Transform。
Component是组件,此时的它更符合名字了。组件只存放数据,没有任何的逻辑代码,并且同Entity的Component将被集合到一起放在内存里,这也有助于搜索时提高内存的命中率。另一方面,Component在传统Unity中,需要继承自Monobehaviour,才能挂在GO上,现在不用了,避免了多次继承下来额外的冗余数据,减少了内存占用的大小。
System是实际的算法逻辑。负责与多线程代码结合,进行数据的处理与转换。
World是部分/全部Entity的集合,可以同时存在多个World,每个World独立包含一个EntityManager与Systems,在世界里面创建出来的一个Entity,只属于这个世界。世界里每个System也只能迭代同一个世界里面的Entity实体数据,World在update时会给System传递所需的Components。
EntityManager是ECS中高效管理Entity的管理器,它负责释放和加载新的Entity。它会将同一Entity标识的Components集合到一起放置,构成Archetype。Archetype下的所有组件将被存放在一块内存中,这称之为chunk。要注意,一个Archetype下可能有多个chunk,每一个chunk的大小是16k,如果空间不足再加就是。但不同Entity拥有不同的组件构成时,则会划分到不同的Archetype。如下图所示:
Entity A和B拥有同样的Components构成,但C少了RigidBody,所以A和B划分在同一Archetype中,但C会划分到另一Archetype中,这样一来,在这张图中迭代所有RigidBody时,就会只在AB所属的Archetype中进行搜索,搜索效率大大提升。由此也可以看出,ECS中是基于Archetype进行内存管理的。