Unity官方DOTS示例学习笔记(二)HelloCube\2. IJobChunk
前一篇:Unity官方DOTS示例学习笔记(一) 下一篇:Unity官方DOTS示例学习笔记(三) 示例的github地址 https://github.com/Unity-Technologies/EntityComponentSystemSamplesEntityComponentSystemSamples-master\ECSSamples\Assets\HelloCube\2. IJobC
·
前一篇:Unity官方DOTS示例学习笔记(一) 下一篇:Unity官方DOTS示例学习笔记(三) 示例的github地址 https://github.com/Unity-Technologies/EntityComponentSystemSamples
EntityComponentSystemSamples-master\ECSSamples\Assets\HelloCube\2. IJobChunk
1.手写(非Unity自动生成)authoring component(不知道怎么翻译这个词)
在上一个例子,authoring component 是用属性[GenerateAuthoringComponent]自动生成的 以下是这个Component的定义,属性是 [Serializable] 而不是[GenerateAuthoringComponent]
[Serializable] public struct RotationSpeed_IJobChunk : IComponentData { public float RadiansPerSecond; }
再来看这个手写的authoring component
[RequiresEntityConversion] [AddComponentMenu("DOTS Samples/IJobChunk/Rotation Speed")] [ConverterVersion("joe", 1)] public class RotationSpeedAuthoring_IJobChunk : MonoBehaviour, IConvertGameObjectToEntity { public float DegreesPerSecond = 360.0F; public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { var data = new RotationSpeed_IJobChunk { RadiansPerSecond = math.radians(DegreesPerSecond) }; dstManager.AddComponentData(entity, data); } } 手写的authoring component必然是一个MonoBehaviour。仔细看Component上的旋转速度是RadiansPerSecond 而 authoring component 上的是DegreesPerSecond 。很显然,如果把Component拖到prefab上,显示的是authoring component的DegreesPerSecond 手写authoring component 需要实现IConvertGameObjectToEntity接口的Convert函数。这个函数的实现就是把这个Component加到EntityManager中去。 文档上说这种方式更灵活。从代码上看是对定义的Component的做了额外的“加工”,也就是最后真正在Job用的component上的数据并不是定义的Component。那如果存在这样的流程,这个定义的数据到真正使用的数据就只会在转Entity的时候做一次。如果用自动生成的方式,那就必然在Job里转,那就是成了每一次线程都转一次。从这个角度来看,手写的确实比自动生成好。
2.IJobChunk
这个例子的System :RotationSpeedSystem_IJobChunk 里面实现了IJobChunk。文档里提到如果用IJobChunk能适应更复杂的情况(这个例子看不出来),更好的性能。因为ECS框架会通过一个ArchetypeChunk在内存的你需要的Component中实例化你的Execute()函数。我理解这里不是去实例化这个Execute()函数,而是实例化Job对象。 Execute函数是Job完成具体工作的函数。即便是不了解Job System也好理解这块。如果我们自己抽象化一个线程的类或者接口,必然要抽象一个用于实现具体功能的函数。事实上ECS的IJobChunk接口里也只定义了这个函数
public interface IJobChunk { void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex); }
要用在System里用IJobChunk需要重载OnCreate函数,并且用EntityQuery的成员变量把需要的Component先存起来。在这个例子里只用到了自己写的RotationSpeed_IJobChunk和内置的Rotation。
protected override void OnCreate() { m_Group = GetEntityQuery(typeof(Rotation), ComponentType.ReadOnly<RotationSpeed_IJobChunk>()); }
3.System里的OnUpdate函数
在这个例子里,OnUpdate里就是对Job的调度了。具体的功能(旋转)都写到了Job的Execute函数里了。实际上上一个例子里线程具体工作(旋转)也在Job里,只是用了lamda表达式而已。 protected override void OnUpdate() { var rotationType = GetArchetypeChunkComponentType<Rotation>(); var rotationSpeedType = GetArchetypeChunkComponentType<RotationSpeed_IJobChunk>(true); var job = new RotationSpeedJob() { RotationType = rotationType, RotationSpeedType = rotationSpeedType, DeltaTime = Time.DeltaTime }; Dependency = job.Schedule(m_Group, Dependency); }
4.Brust优化
在Job的实现上加[BurstCompile] [BurstCompile] struct RotationSpeedJob : IJobChunk
5.ComponentType.ReadOnly
protected override void OnCreate() { m_Group = GetEntityQuery(typeof(Rotation), ComponentType.ReadOnly<RotationSpeed_IJobChunk>()); }
再仔细看System里重载的OnCreate函数。调用的GetEntityQuery中传入了两个参数,一个是typeof(Rotation) 一个是ComponentType.ReadOnly<RotationSpeed_IJobChunk>()。关于这个ComponentType.ReadOnly文档中是这么解释的 The query uses ComponentType.ReadOnly instead of the simpler typeof expression to designate that the system does not write to RotationSpeed. Always specify read-only when possible, since there are fewer constraints on read-only access to data, which can help the Job scheduler execute your Jobs more efficiently. 详见https://docs.unity3d.com/Packages/com.unity.entities@0.11/api/Unity.Entities.EntityQuery.html 对于这个,我的理解是:一个多线程是否高效,跟怎么访问数据是有关系的。如果数据是只读的,线程是可以不加锁的。如果数据是读写的,线程需要加锁(这不是绝对的,但至少会做更多事情)。所以文档说这样会让你的Job的调度更高效。在这里旋转速度Componet:RotationSpeed_IJobChunk是只读的。而Rotation不是只读的,旋转就是通过改变它的旋转值而实现的。
另外,更复杂的情况下,可以EntityQueryDesc来指定component types All: 组件必须有这些archetype Any: 组件至少得有Any列出的archetype None: 组件不能有None列出的 具体可以参考https://docs.unity3d.com/Packages/com.unity.entities@0.11/manual/chunk_iteration_job.html protected override void OnCreate() { var queryDescription = new EntityQueryDesc() { None = new ComponentType[] { typeof(Static) }, All = new ComponentType[] { ComponentType.ReadWrite<Rotation>(), ComponentType.ReadOnly<RotationSpeed>() } }; m_Query = GetEntityQuery(queryDescription); }
更多推荐
所有评论(0)