IJobEntity 的执行单位是 Entity
,而 IJobChunk 的执行单位是 Chunk
Chunk

chunk 相当于一个存储数据的区域,其中:
- 单个 chunk 的内存为 16kb。
- 单个 chunk 只存储相同 archetype 的 entity。如上图,如果我们从 Entity A 中删除 Renderer 组件,那么其将从 M 转移到 N。
在 DOTS 当中会把相同组件的实体放在一起,也就是 chunk。把相同类型的数据连续存放在一块内存里,可以提高读取数据的效率。实际上 chunk 被划分为 parallel arrays
(就当作给其翻译为并行数组吧,此处的意思是数组平行存储而不是具有任何嵌套关系)。
此处给出一个例子:

此处的 chunk 存储的 archetype 由 Component A, B, C 构成。其可以存储的 entity 数量约为:
1
| int maxEntity = 16539 / (sizeof(id) + sizeof(A) + sizeof(B) + sizeof(C))
|
如图所示:这个 chunk 被划分为四个逻辑数组,每个数组的大小都是 maxEntities
:一个数组用于 ID,一个用于 A 组件,一个用于 B 组件,一个用于 C 组件。当然,块还存储了这些数组的偏移量 以及 当前存储的实体个数。chunk 的第一个实体存储在所有四个数组的索引 0 处,第二个实体存储在索引 1 处,第三个实体存储在索引 2 处,依此类推。如果块有 100 个存储的实体,但我们随后删除了索引 37 处的实体,则计数将减少到 99,索引 99 处的实体将向下移动到索引 37 以填补空白。也就是使用末尾元素去填补。
Archetype
根据上面对 chunk 的介绍,差不多已经对 archetype 有了一定的概念。

刚刚才说过,一个 chunk 的大小只有 16kb 对吧。当 entity 太多的时候,我们一个 chunk 就会遇到到达容量上限的问题了。那此时就会再开一个 chunk,如上图,虽然有三个 chunk,但是它们都属于一个原型,也就是一个 archetype。archetype
也就是存放了相同 component
的类型。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| namespace HelloCube.IJobChunk { public partial struct RotationSystem : ISystem { [BurstCompile] public void OnCreate(ref SystemState state) { state.RequireForUpdate<Execute.IJobChunk>(); }
[BurstCompile] public void OnUpdate(ref SystemState state) { var spinningCubeQuery = SystemAPI.QueryBuilder().WithAll<RotationSpeed, LocalTransform>().Build();
var job = new RotationJob { TransformTypeHandle = SystemAPI.GetComponentTypeHandle<LocalTransform>(), RotationSpeedTypeHandle = SystemAPI.GetComponentTypeHandle<RotationSpeed>(true), DeltaTime = SystemAPI.Time.DeltaTime };
state.Dependency = job.ScheduleParallel(spinningCubeQuery, state.Dependency); } }
[BurstCompile] struct RotationJob : Unity.Entities.IJobChunk { public ComponentTypeHandle<LocalTransform> TransformTypeHandle; [ReadOnly] public ComponentTypeHandle<RotationSpeed> RotationSpeedTypeHandle; public float DeltaTime; public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask) { Assert.IsFalse(useEnabledMask);
var transforms = chunk.GetNativeArray(ref TransformTypeHandle); var rotationSpeeds = chunk.GetNativeArray(ref RotationSpeedTypeHandle); for (int i = 0, chunkEntityCount = chunk.Count; i < chunkEntityCount; i++) { transforms[i] = transforms[i].RotateY(rotationSpeeds[i].RadiansPerSecond * DeltaTime); } } } }
|
相关链接: