Job System之Hello World

洪流学堂,让你快人几步。你好,我是跟着大智学Unity的萌新,我叫小新,最近在探索DOTS。
之前说了那么多枯燥的原理,咱们来看看Job System的代码如何写吧。

创建Job

创建Job需要定义一个结构体,实现IJob接口。实现了IJob接口之后,就可以让这个Job和其他Job并行运行了。
到这呢,就可以给Job一个真正的定义了:Job是一个统称,任何实现了IJob接口的结构体,都可以成为一个Job。
创建Job的步骤如下: 1、创建一个实现IJob接口的结构体 2、给结构体添加所需的成员变量,可以使用blittable类型或者NativeContainer类型。 3、在结构体中添加一个Execute方法,具体执行的任务在这个方法里实现。
当执行Job时,Execute方法会在一个内核上执行完毕。
注意:设计job时,记住job操作的是数据的拷贝,除非使用NativeContainer。所以,在主线程访问job数据的唯一方法就是写入NativeContainer。
实例代码如下:
// 这个Job的功能:将两个浮点数相加 public struct MyJob : IJob { public float a; public float b; public NativeArray<float> result; public void Execute() { result[0] = a + b; } }

调度Job

创建Job后,如何执行一个Job呢?
这时候需要调度Job,调度Job的步骤如下: 1、实例化Job 2、构造Job的数据 3、调用Schedule方法。
调用Schedule方法会将Job放到Job执行队列的适当位置。一旦安排了Job后,就不能再中断job执行了。
注意:只能在主线程中调用Schedule方法。
// 创建一个长度为1的native array用来存储job执行后的结果 NativeArray<float> result = new NativeArray<float>(1, Allocator.TempJob); // 设置job的数据 MyJob jobData = new MyJob(); jobData.a = 10; jobData.b = 10; jobData.result = result; // Schedule JobHandle handle = jobData.Schedule(); // 等待job执行完毕 handle.Complete(); // 获取result中的数据 float aPlusB = result[0]; // 一定要释放native array申请的内存 result.Dispose();

Job的依赖关系

很多时候,Job并不是独立运行的,需要依赖前一个Job的结果,这时候如何调度呢?

JobHandle

当调用Schedule方法时,会返回一个JobHandle。你可以使用这个JobHandle作为其他job的依赖项。具体方法就是将第一个job的JobHandle传给第二个job调用Schedule时的参数,例如:
JobHandle firstJobHandle = firstJob.Schedule(); secondJob.Schedule(firstJobHandle);
那如果一个job有多个依赖项怎么办呢?这时候可以用JobHandle.CombineDependencies方法合并他们。具体如下:
// 声明一个JobHandle的NativeArray数组 NativeArray<JobHandle> handles = new NativeArray<JobHandle>(numJobs, Allocator.TempJob); // 将多个handles放到数组中 // 将多个handles合并到一起 JobHandle jh = JobHandle.CombineDependencies(handles);

等待Job执行完毕

在主线程中如何等待Job执行完毕呢?可以调用JobHandle中的Complete方法强制等待。Complete方法执行过后,你就可以在主线程中安全地访问job中使用的NativeContainer了。
注意 当你调用job的Schedule方法后,job并不会立即开始执行。如果你在主线程中等待job执行完毕,并且你需要访问job使用的NativeContainer中的数据时,你可以调用JobHandle.Complete方法。这个方法会启动job的执行。调用JobHandle的Complete方法后,会将job的NativeContainer所有权还给主线程。所以只有调用过JobHandle上的Complete方法后,主线程才能安全的访问NativeContainer中的数据。同理,也可以调用依赖此job的JobHandle上的Complete方法。例如,你可以调用jobA的Complete方法,也可以调用依赖jobA的JobB的Complete方法。这两种情况下,主线程都可以安全访问jobA使用的NativeContainer。

实例代码

Job代码:
// Job:两个浮点数相加 public struct MyJob : IJob { public float a; public float b; public NativeArray<float> result; public void Execute() { result[0] = a + b; } } // Job:给一个值加一 public struct AddOneJob : IJob { public NativeArray<float> result; public void Execute() { result[0] = result[0] + 1; } }
主线程代码:
// 创建存储结果的NativeArray NativeArray<float> result = new NativeArray<float>(1, Allocator.TempJob); // 设置job #1 MyJob jobData = new MyJob(); jobData.a = 10; jobData.b = 10; jobData.result = result; // 调度job1 JobHandle firstHandle = jobData.Schedule(); // 设置job2 AddOneJob incJobData = new AddOneJob(); incJobData.result = result; // 调度 job2,依赖job1 JobHandle secondHandle = incJobData.Schedule(firstHandle); // 等待job2执行完毕 secondHandle.Complete(); // 访问结果 float aPlusB = result[0]; // 释放内存 result.Dispose();

总结

这一节是Job System的Hello World,和其他Hello World一样,并不能解决什么实际问题。等咱们基础知识入门完毕后,再一起来看看Job System的威力。

扩展阅读

【扩展学习】在洪流学堂公众号回复DOTS可以阅读本系列所有文章,更有视频教程等着你!
呼~ 今天小新絮絮叨叨的真是够够的了。没讲清楚的地方欢迎评论,咱们一起探索。
我是大智(微信:zhz11235),你的技术探路者,下次见!
别走!点赞,收藏哦!
好,你可以走了。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值