[Unity ECS 入门]4.筛选实体数据的方式3——IJobForEach(已废弃)

笨木头  2019-12-5 14:24   ECS入门   阅读(2,134)   7条评论

转载请注明,原文地址:http://www.benmutou.com/archives/2801
文章来源:笨木头与游戏开发

来自2020.04.28的说明:

网友提示,0.9.1版本下的Entities已经放弃使用 IJobForEach,木头本人当时学习的是0.3版本,所以,理论上来说,本文已作废。

 

上一篇我们介绍了JobComponentSystem的基础用法,其实还有更多的用法,这次来介绍一下IJobForEach。

同样是用于筛选实体数据,执行一些逻辑操作,但是IJobForEach比起单纯地使用Entities.ForEach,在大部分情况下会有更优秀的性能。

1.IJobForEach

我们还是用之前的代码,但是,System类又要做一些改动:

现在,OnUpdate里的逻辑都放到一个RotationSpeedJob里处理,然后通过调用这个Job的Schedule函数返回了一个JobHandle对象。和之前有点像,只不过是用一个称之为Job的东西把逻辑封装了。

 

RotationSpeedJob继承了IJobForEach接口,然后实现了Execute 函数。

Execute函数里做的事情和之前类似,修改实体的旋转值。

 

但是,这里有一点不一样,很重要的一点——Execute里没有使用Entities.ForEach了。

是的,每一个IJobForEach,只会处理一个实体的组件对象。

并且,这些Job是可以并行处理的,这就是JobComponentSystem配合IJobForEach的优势——并行。

我们来理一理:

a. JobComponentSystem的OnUpdate函数的主要逻辑移到了RotationSpeedJob中处理。

b. JobHandle对象需要通过IJobForEach来返回,实际上能返回JobHandle对象的不仅仅是IJobForEach这种接口,还有其他的,即,JobComponentSystem可以和若干种不同类型的Job配合。

c. IJobForEach接口需要实现Execute函数,函数参数指定了需要筛选的组件类型(可多个),以此来获得所需实体的组件对象,然后进行读写操作。指定的组件类型需要和接口声明的泛型对应,比如我们的接口声明的泛型是: IJobForEach<Rotation, RotationSpeed_ForEach>,和Execute函数的参数类型是对应的。

d. Execute函数只能对单个实体的组件(组件可以多个)进行操作。

e. IJobForEach,我们称之为Job,Job是可以并行执行的(多线程),因此能提升性能。

f. 请注意,Execute的参数可以带有ReadOnly特性,代表获取的这个类型的组件是只读的,不能进行写操作。

g. 如果某个Job对某个组件对象进行了写操作,则其他需要读取这个组件对象的Job无法并行执行,相当于锁住了。

关于JobSystem的知识,我现在还没有掌握,我会在后续的教程里和大家分享。

2.运行

好了,看看效果吧,除了System发生了改变,其他内容没变,大家修改了System类后,运行程序,结果是是一样的。

3.要注意的地方,重要!

利用IJobForEach时,系统会自动并行处理,但是,它只会按照块(Chunk)来并行处理。

 

什么是块(Chunk)?因为这是一个很重要的概念,我会在下一篇单独讲(重要,但理解起来很简单)。

 

虽然现在大家还没有块的概念,但是可以先注意一下。

如果我们的实体数量很少,筛选出来的实体刚好都在一个块里。

那么,IJobForEach其实是没有帮助的,因为它是按照块为单位进行并行处理的,只有一个块的话,也就不存在并行了。

 

大家看看下一篇关于块(Chunk)的解释,就能理解这段话的意思了。

 

注意,本系列教程基于DOTS相关预览版的Package包,是预览版,不代表正式版的时候也适用。

转发本系列文章的朋友请注意,带上原文链接和原文日期,避免误导未来使用正式版的开发者。

7 评论

  1. 0.9.1版本下的Entities已经放弃使用 IJobForEach了,希望博主能修改一下文章(注明这个方法在某某版本被放弃了)

  2. 这里有个疑问,假如说通过Rotation+RotationSpeed_ForEach筛选出来的实体不止一个,那IJobForEach这种方式实现的方法会处理哪一个呢?

    1. 都会处理的,每一个被筛选出来的实体(组件)都会执行一次Excute函数。
      这也是我们要转换的思维,在ECS中,我们只针对数据进行操作,只要这些数据满足我们的筛选条件,不断有多少个,我们都做一样(或类似)的处理。

      1. 就是您说了一个“Execute函数只能对单个实体的组件”,这个有点没理解什么意思,理论上说entities.foreach是不是可以理解为一个循环遍历,所以拥有筛选组件的实体都会旋转。但是继承了Ijobforeach后,这个遍历是在哪里做的呢?

发表评论

电子邮件地址不会被公开。 必填项已用*标注