Technology DOTS - chaolunner/CloudNotes GitHub Wiki
多线程式数据导向型技术堆栈
-
.Net Core比C++慢2倍
-
Mono比.Net Core慢3倍
-
IL2CPP比Mono快2-3倍,IL2CPP与.Net Core效率相当,但依然比C++慢2倍
-
Unity使用Burst编译后可以让C#代码运行的效率比C++更快
-
C# class类型数据的内存分配在堆上,无法主动释放,必须等到.Net垃圾回收才可真正清理
-
IL2CPP虽然将IL转成C++代码,实际还是模拟了.Net的垃圾回收机制,所以效率并非等同于C++
-
HPC# 就是NativeArray可代替数组T[] 数据类型包括(float,int,uint,short,bool...),enums,structs和其他类型的指针
-
NativeArray可以在C#层分配C++中的对象,可以主动释放不需要进行C#的垃圾回收
-
Job System中使用的就是NativeArray
void Update() { Profiler.BeginSample("NativeArray"); NativeArray<Vector3> velocity1 = new NativeArray<Vector3>(1000, Allocator.Persistent); for(int i = 0; i < velocity1.Length; i++) { velocity1[i] = Vector3.zero; } Profiler.EndSample(); velocity1.Dispose(); Profiler.BeginSample("Vector3[]"); Vector3[] velocity2 = new Vector3[1000]; for(int i = 0; i < velocity2.Length; i++) { velocity2[i] = Vector3.zero; } Profiler.EndSample(); }
- IJob是一个一个开线程任务,因为数据是顺序执行的所以它可以保证正确性
- 如果想让线程任务真正的并行,那么可以用IJobParallelFor
- 一旦线程任务并行的话,就意味着数据执行的顺序不是线性的,每一个Job里的数据不能完全依赖上一个Job执行后的结果
- [ReadOnly]声明数据是否只读,如果数据是只读的,意味着这个数据不需要加锁
- 如果不声明默认数据是Read/Write的,数据一旦需要改写,那么Job就一定要等它
- 然而这一切Unity都已经帮我们做好,我们不需要自己做加解锁逻辑
- Burst编译器是以LLVM为基础的后端编译技术
- 编译器的原理分为5个步骤:源代码->前端->优化器->后端->机器码
- LLVM定义了个抽象语言IR,前端负责将源码(C#)编译成IR,优化器负责优化IR,后端负责将IR生成目标语言这里就是机器码
- 正是因为抽象语言IR的存在,所以LLVM支持的语言很多,而且也方便扩展C#,ActionScript,Ads,D语言,Fortran,GLSL,Haskell,Java字节码,Objective-C,Swift,Python,Ruby,Rust,Scale等语言
- LLVM代码是开源的,所以Unity很适合用它来做Burst的编译
- 遗憾的是LLVM对C#的GC做的并不好,所以Burst只支持值类型数据编译,不支持引用类型数据编译
-
Unity.Mathematics提供矢量类型(float4,float3...),它可以直接映射到硬件SIMD寄存器
-
Unity.Mathematics的Math类中也提供了直接映射到硬件SIMD寄存器
-
这样原本CPU需要一个个计算的,有了SIMD可以一次性计算完毕
-
需要注意的是Unity之前的Math类默认是不支持映射SIMD寄存器的
CPU接收到指令后,它会最先向CPU中的一级缓存(L1 Cache)去寻找相关的数据,虽然一级缓存是与CPU同频运行的,但是由于容量较小,所以不可能每次都命中。这时CPU会继续向下一级的二级缓存(L2 Cache)寻找,如果所需要的数据在二级缓存中也没有的话,会继续转向三级缓存(L3 Cache),如果还是没有则会从内存(主存)拿取一段连续的数据到缓存中来。
在Unity ECS中,并不只是对Entity进行分组,而是连着Entity对应的Component一起进行分组,称作Archetype。每一种Component都存放在连续内存里,而这些Component对应的内存又被分割成固定长度被打包在一块固定大小的内存里,称作Chunk,满足一类Archetype的多个Chunk又被一个LinkedList连接起来存于满足条件的Archetype。
而且ECS下的Component里面只包含所需要用到的数据,不需要继承自MonoBehaviour,内存大为节省。同时由Component类型组合而成的Archetype,会在内存中高度紧密的排列。这就使得CPU的Cache命中率非常的高,效率大幅提升。