Dots初探和原理分析

1.什么是DOTS

DOTS是Data-Oriented Tech Stack的缩写,中文名:多线程数据导向型技术堆栈

DOTS由以下3部分内容构成

ECS Entity Component System
C# Job System
Burst Compiler

Dots的官方数据
在这里插入图片描述

450w个mesh render
10万个音频文件同时播放
5k个不同的汽车模型
20万个不同的建筑模型
稳定60帧

DOTS原理

  • ECS 用于编写高性能代码
  • Job System 用于高效运行多线程代码
  • Burst Compiler 用于生成高度优化的本地代码

这三者是完全不同的两个概念,可以分开使用,但结合使用才能发挥最大优势

  • ECS: 缓存友好,利用struct去掉GC
  • JOBS:充分利用多线程
  • BURST:SIMD,LLVM 编译优化

了解完DOTS的概念定义,接着来剖析一下为什么DOTS能带来如此显著的性能提升.
首先我们需要知道缓存友好和局部性原理:

缓存友好

CPU缓存是什么?

CPU缓存的定义为CPU与内存之间的临时数据交换器,它的出现是为了解决CPU运行处理速度与内存读写速度不匹配的矛盾——缓存的速度比内存的速度快很多。CPU缓存一般直接跟CPU芯片集成或位于主板总线互连的独立芯片上。(现阶段的CPU缓存一般直接集成在CPU上)CPU往往需要重复处理相同的数据、重复执行相同的指令,如果这部分数据、指令CPU能在CPU缓存中找到,CPU就不需要从内存或硬盘中再读取数据、指令,从而减少了整机的响应时间。

  • CPU访问缓存的原理
    下面这张图是cpu内核和各级缓存的概念图,距离内核越近的速度越快,容量越小,距离内核越远的速度越慢容量越大.
    在这里插入图片描述

下图为真实CPU内部结构
在这里插入图片描述

局部性原理

时间局部性:在一个具有良好的时间局部性的程序当中,被引用过一次的内存位置,在将来一个不久的时间内很可能会被再次引用到。

空间局部性:在一个具有良好的空间局部性的程序当中,一个内存位置被引用了一次,那么在不久的时间内很可能会引用附近的位置。

根据空间局部性原理,CPU把上述内容放到缓存里面不会只放几个字节,一般会将所在的物理页内容都加载到缓存,例如4KB

如何提高CPU缓存命中率

  • 什么是缓存行
    CPU缓存由缓存行构成,每个缓存行占用64字节

  • 缓存行是怎么被浪费掉的
    数据浪费:假设需要移动一个物体的x轴方向的坐标,传统的做法是修改物体的localPosition,但localPosition中还包含有y和z,虽然我们并不需要修改y和z,但是由于最小单位就是一个Vector3,因此多余的y和z就白白占用了宝贵的缓存,造成了浪费.
    多余组件浪费:当我们需要修改某个GameObject的坐标时,一定是得到该GameObject本身,再获取其transform组件,再修改此transform组件的localPosition,虽然最终和transform没什么关系,但却不得不缓存此transform组件,造成浪费.

ECS和普通数据存储之间的区别

ECS要求所有相同的组件在内存中都排列在一起

Chunk和Archetype
ECS中的数据以Chunk为单位进行数据排列,相同结构的Entity会被放到同一个类型的Chunk中.
在这里插入图片描述
多个Chunk组成Archetype.
在这里插入图片描述
ECS运作示意图
在这里插入图片描述
Entity身上挂载了Component,多个不同的Component数据交由System进行运算,运算结果再以Component的形式返还给Entity,完成一轮循环.

Entity和普通类对象

  • 不能使用继承进行扩展
  • 设计模式的更新,严格使用组合替代继承

把GameObject转Entity
unity官方提供了把传统GameObject转换为Entity的接口,但经实际测试,转换效率低,转换5000个GameObject需要数秒时间,不具备商用价值,建议直接创建Entity,再往其身上挂载Component,虽然繁杂了一点,但是运行效率能得到保障.

System生命周期
在这里插入图片描述

2.JobSystem

JobSystem和常见的多线程编程没有太大的区别,具体原理不再赘述.
JobSystem是整个DOTS中理解成本较低,但使用成本较高的部分.
unity包揽了几乎所有多线程调度,工作压力自动分配等传统多线程的工作,我们只需要按照unity定好的规则和接口进行套用就可以了,理解上几乎没有额外成本,但由于必须按照unity定好的接口来进行编码,同时需要记忆不少接口,因此使用成本略高,加上最近的几个版本多线程方面的接口不停在调整和增减,因此也增加了不少使用成本.

3.Burst编译器

Burst编译器是由开源LLVM二次开发所得,由于Unity必须兼顾大量的跨平台特性,同时LLVM也确实是个优秀的编译器,因此untiy选择基于LLVM来开发自己的编译器.

说道Burst编译器我们必须先了解一下SIMD指令优化

SIMD是什么

SIMD全称Single Instruction Multiple Data,单指令多数据流,能够读取多个操作数,并把它们打包在大型寄存器的一组指令集。一次获取多个操作数后,存放于一个大型寄存器,再进行运算,从而达到一条指令完成对多个对象计算的效果,实现加速。

SIMD可一次执行多条命令
在这里插入图片描述

Unity新数学库

unity引入了全新的数学计算库:Mathematics
Mathematics使用了SIMD并行计算
在这里插入图片描述
由于3D图形学中,涉及到大量的矩阵运算,因此SIMD刚好可以充分发挥其效用,大大提升并行运算的速度.

如何使用burst编译器

使用Burst编译器几乎是傻瓜式的,只需要在函数定义前加上如下申明即可:

[BurstCompile]

下图为C#到机器码的过程
在这里插入图片描述

unity官方提供能了Burst编译器的处理流让大家看到具体发生了什么事情:
在这里插入图片描述

Assembly:源代码
.Net IL:转换成IL
LLVM IR(Unoptimized):转换成没经优化的IR中间代码
LLVM IR(Optimized):转换成优化后的IR中间代码
LLVM IR Optimisation Diagnostics:最终的机器码

Burst编译效果对比

.Net Core比c++慢2倍
mono比.Net Core慢3倍
IL2CPP比mono快2~3倍
IL->LLVM IR比.Net Core快3倍

HPC#

C# chass类型数据的内存分配在堆上,无法通过代码主动释放,必须等到.NET垃圾回收才可真正清理
IL2CPP虽然将IL转换成C++代码,但垃圾回收使用的Boehm(贝姆),所以效率并非等同于c++
HPC#就是NativeArray可代替数组T[]数据类型包括值类型(float,int,uint,short,bool),enums,structs和其他类型的指针
NativeArray,NativeList系列API可以在C#层分配C++中的对象,可以主动释放不需要进行C#的垃圾回收
JobSystem中使用的就是NativeArray

总结:ECS+JobSystem+burst+SIMD+hpc#造就了DOTS如此夸张的运行效率

4.Hybird Renderer

由于传统的模型,贴图,动画等并不能在ECS架构下正常运行,因此Unity另外开发了一套专门适配ECS的渲染系统Hybird Renderer
不过当下的Hybird Renderer模式仍然很不完美,不支持动画系统+蒙皮动画,只支持简单的缩放和角度调整,个人觉得还没达到商用的程度.

5.如何在已有项目中嵌入dots

目前整个DOTS在不停的迭代中,整个ECS及JOBS已相对成熟,市面上已有部分公司在商业项目中进行了探索和尝试,但DOTS在渲染部分仍然有很多缺陷,因此可以利用传统的动画和蒙皮组件来制作动画,使用DOTS来替代原本MonoBehaviour来进行高强度的运算,得到运算结果后传递给传统GameObject,由GameObject来进行呈现.

6.如何安装dots

Dots可在PackageManager中进行安装,本文章是基于下面的版本进行的学习和探索:
在这里插入图片描述
目前网上有部分DOTS的学习示例工程,但由于Packge Manager的缘故,很多工程并未标明所使用的DOTS版本,导致大部分工程都无法正常运行,这里提一个小tips:

使用所下载的工程所用的Unity版本来打开工程,而不是自己电脑上当前所使用的Unity版本,这样在版本匹配的前提下,Unity能自动匹配之前所使用的DOTS版本,这也是我在学习的过程中摸索出来的小窍门.

7.Dots适合的使用场景

Dots在游戏开发上能提供超乎想象的运行效率,但是并不是所有游戏都适合使用Dots,目前Dots更适合有大量单位,并且每个单位需要进行大量雷同运算的场景,如果是不太追求运算效率的简单游戏,使用DOTS反而使得整个架构变得不必要的复杂,维护成本也会同时变高.

8.DOTS Demo展示:

如下demo分别用传统的MonoBehaviour,ECS,ECS+JOBS 3种方式对同样的逻辑运算进行了测试,可以很明确的区分出3者之间显著的性能差别

https://github.com/CraneInForest/DOTS_SAMPLE.git
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值