面向数据设计与Unity3d ECS笔记
1、部分历史[*]2002 GDC,《A Data-Driven Game Object System》 http://scottbilas.com/files/2002/gdc_san_jose/game_objects_slides.pdf 用组合不用继承来实现游戏对象的实例,运行时组合带来了不少优势
[*]2006 《Out of Tar Pit》http://curtclifton.net/papers/MoseleyMarks06a.pdf 感觉这个可以认为是面向数据方法或ECS在软件工程方面的理论基础
[*]2007 《Entity Systems are the future of MMOG development》Entity Systems are the future of MMOG development - Part 1 这个系列基本上已经把ECS的概念阐述的很清晰了
[*]2010 《 Introduction To Data Oriented Design 》面向数据的性能优势在这里已经基本总结出来了
[*]?~2018《 Data-Oriented Design》 Richard Fabian https://www.dataorienteddesign.com/dodbook/ 作者应该跟进面向数据挺长时间了,软件工程层面与性能方面都有涵盖,但感觉作者比较偏激,不能除了面向数据就不能有别的开发方法了吧
[*]2015 《 Comments on Data Oriented Design》 Comments on Data Oriented Design – Part I Comments on Data Oriented Design – Part II 一些思考,似乎没有新的东西
[*]2020 《 Data oriented design is not about SoA and ECS》 Data oriented design is not about SoA and ECS – Alex Dixon 继续一些思考,好像也没啥新东西
2、概念
[*]Entity---仅仅标识实体,没有方法、没有数据
[*]Component---代表数据,没有方法
[*]System---与某类或几类Component相关的行为,主动处理,集合处理
[*]依赖某种查询机制,来获取一个Entity集合上各Entity的符合条件的Component集合
[*]游戏对象数据库(key/Data/Query)
[*]关系数据库与关系代数
[*]Unity3d ECS的EntityQuery
3、FRP范式论文《Out of Tar Pit》
[*]复杂性是软件工程的核心问题
[*]三种复杂性来源
[*]状态引起的复杂性(State)
[*]控制引起的复杂性(Control)
[*]代码量引起的复杂性(代码量的增长需要脑力的平方增长来理解)
[*]三种主要的编程范式
[*]命令式(以面向对象为代表讲述)
[*]函数式(Haskell、ML、Lisp)
[*]逻辑编程(Prolog)
[*]降低复杂性的解决方案
[*]分离状态与控制,亦即用户数据与核心逻辑
[*]分离本质状态、逻辑与偶然状态、逻辑,消除不必要的偶然状态、逻辑
[*]提出一种新的编程范式—函数关系式(FRP)
4、提升性能的原理
[*]Cache友好(0~10倍提升)
[*]保证遍历时访问的数据连续存放并且只包含需要访问的数据
[*]SOA---数组的结构
[*]SOAOS--结构的数组的结构
[*]Unity3d ECS的Component Data Chunk
[*]SIMD(0~4倍提升)
[*]multithread(0~8倍提升)
[*]Job System
[*]分支预测,避免if/else(感觉提升不明显,同时很难避免)
[*]异构编程(严格说与ECS无关,但ECS好像通常就是在实现异构编程的cpu部分)
[*]cpu--延迟消除架构,利用cache与缓存来消除延迟
[*]gpu--延迟隐藏架构,利用大量并发与快速切换来隐藏延迟(SIMT)
5、unity ECS 0.17
[*]system可以使用托管对象,job不可以,猜测原因是引用类型互相关联无法进行编译时分析,而job要运行在多线程必须保证没有数据访问冲突,因此不开启burst编译不使用多线程的job是可以使用托管数据的
[*]component里不能使用数组,nativearray也不可以(官方说这个是暂时的限制,后续会努力消除)
[*]shared component+archtype确定了chunk,目前看chunk的组织可以认为是固定的,或者说数据目前组织为2个层级:thunk与component data
[*]应优先用systembase和Entities.ForEach,除IJobEntityBatch外,其它IJob开头的接口已经不推荐使用
[*]generic component应该是最多使用的component类型,后续应该会一直存在
[*]buffer component用来记录动态变化的数据,这应该是为了弥补component里不能使用数组的限制
[*]chunk component加IJobEntityBatch可以用来给每组同步数据或汇总每组数据
[*]因为chunk与component只有2级,所以只能用于2个层级的概念,比如一个部分作为一个整体可以接受指令,这些指令可以在部队逻辑里暂存到chunk component上,然后在IJobEntityBatch job里同步到部队里的各个单位。
[*]但是如果部队分为多个小队,每个小队再由单位构成这样的三层结构就没有类似的机制了
[*]Blob Asset用来保存只读的信息,可以用于配置数据,能在component里使用
[*]这看来是在ECS里访问配置数据的官方途径
[*]否则可能就只能将配置数据复制多份放到component data上了
[*]在system里使用元素是struct的托管队列可以在system间传递信息,通过局部变量闭包,job里也能访问
[*]system的惯用法其实是fork and join的多线程风格
6、一些问题
[*]Unity3d ECS的版本目前还是早期实验性的,据说0.50版本2022年Q1推出,之后是1.0版本,但1.0版本只考虑支持unity 2022及以上版本
[*]Unity3d ECS可能存在不必要的内存拷贝,在移动设备上对内存带宽有一定影响,基于struct的开发方式非常不自然,开发效率较低
[*]chunk的组织方式只能是2级结构,对数据组织与遍历方式的设计有很大的约束
[*]各System间传递信息有时候还是需要借助非ECS的方式,很难仅仅借助component data来传递信息(不是共享信息)
[*]对功能逻辑,往往数据互相关联,component与system的拆分并不容易
[*]system拆分的依据很模糊(感觉仍然得是功能导向的),性能的提升仍然需要借助profiler来确定,很难在开发过程中进行大致判断
[*]性能提升的技术原理来源于硬件底层,与问题域是割裂的,并且是实现细节相关的,在设计早期很难兼顾(因为此时如何实现还很模糊)
7、从面向对象到面向数据
[*]感觉面向数据方法依赖实现细节,所以不太适合在分析与设计层面使用,一种可能的方式是设计时仍然采用适合问题域的方法,然后性能要求高的部分与面向数据开发方法结合
[*]在实现上,可采用传统开发方法来为ECS准备数据与进行调度
[*]这种调度可能是单向的,也就是从传统方法过渡到面向数据方法后,不宜再返回到传统方法(过程而非函数)
8、native实现
[*]采用c++来实现ECS,感觉可能会更纯粹,比如内存拷贝或许更少,有机会应该试一试,不过缺少burst编译器,simd指令就需要自己来写了
[*]rust是否可以用来实现ECS?rust语言的所有权概念似乎能有效的减少内存拷贝。
页:
[1]