网易首页 > 网易号 > 正文 申请入驻

Unity 中文课堂 | DOTS课程系列:C# Job System精要

0
分享至

C# Job System 是 Unity 从 2018 开始提供给用户的一个非常强大的功能,它允许用户以一种低成本的方式书写高效的多线程代码。

Unity 中文课堂的官方免费课程《DOTS 课程系列 | C# Job System 精要》将从以下方面讲解 C# Job System,点击阅读原文,即可解锁完整教程。

什么是 C# Job System?

IJobFor

Thread Local

Pointers & InterLocked

Batches & False sharing

Custom batch & Kick jobs

SoA vs AoS

什么是C# Job System?

C# Job System 是 Unity 从 2018 开始提供给用户的一个非常强大的功能,它允许用户以一种低成本的方式书写高效的多线程代码。我们先通过一个 Demo 来一步一步揭开 C# Job System 的面纱:

首先我们先来定义一个 Job


public struct AddJob : IJobpublic float a;public float b;public NativeArray result;
public void Execute()result[0] = a + b;

我们最先能观察到的就是 AddJob 实现了 IJob 接口,IJob可以让我们调度(Schedule)一个在单一工作(worker)线程里执行的任务。其次我们可以看到 AddJob 是一个 struct。

我们再来看一下 AddJob 里的变量部分:


public float a;public float b;public NativeArray result;

Job 中的变量我们仅可以使用blittable types或者 Unity 为我们提供的NativeContainer容器,比如引擎内置的 NativeArray 或者 com.unity.collections package 中提供的容器类。

blittable types:

https://en.wikipedia.org/wiki/Blittable_types

NativeContainer:

https://docs.unity3d.com/Manual/JobSystemNativeContainer.html

注:为什么只能使用 blittable types?这是因为 C# Job System 使用了 Unity 内部的 native job system,C# Job System 会与 native job system 共享工作线程。为了达到这个目的,C# 中的 Job 数据需要被拷贝到 native 层来运行计算代码,blittable types 在这个拷贝过程中不需要做数据转换,因此 blittable types 在这里是必须的。不仅如此 blittable types 还有着其他的好处,我们会在后面的例子中看到。

让我们来总结一下声明一个 Job 的要点

创建一个实现了 IJob 接口的 struct。

在 struct 中声明 blittable types 或者 NativeContainer 的变量。

在 Execute() 方法中实现 Job 的逻辑。

好,通过上面几步我们就成功创建了我们的 AddJob 。接下来我们来看一下如何调度(Schedule)一个 Job 以及如何获得 Job 执行后的结果:


var job = new AddJoba = 1,b = 2,result = result
var handle = job.Schedule();handle.Complete();Debug.Log($"result = {result[0]}");

调度(Schedule)一个 Job是比较简单的,只需要调用 Schedule() 方法就可以了。这里比较有意思的是 Complete() 方法,在我们需要读取执行结果之前需要调用 Complete() 方法。但是 Complete() 不一定在 Schedule() 之后立即调用,也不一定在当前帧必须调用,也就是说一个 Job 本身不受 Update() 限制可以跨帧运行。当一个 Job 需要跨帧运行的时候,我们需要使用 IsCompleted 属性来判断 Job 是否执行完毕。


private void Update()if (handle.IsCompleted)handle.Complete();Debug.Log($"result = {result[0]}");

注:即使 IsCompleted 返回 true,也必须要调用 Complete() 方法。具体可以参考 C# Job System tips and troubleshooting。

C# Job System tips and troubleshooting:

https://docs.unity3d.com/Manual/JobSystemTroubleshooting.html

这样我们就实现了了一个最简单的 Job,这里我给出完整的 Demo 代码,方便大家进一步理解上面介绍的内容:


public class AddJobBehaviour : MonoBehaviourpublic bool longRunningJob;private JobHandle handle;private NativeArray result;
public struct AddJob : IJobpublic float a;public float b;public NativeArray result;
public void Execute()result[0] = a + b;
private void Start()result = new NativeArray(1, Allocator.Persistent);
var job = new AddJoba = 1,b = 2,result = result
handle = job.Schedule();
if (!longRunningJob)handle.Complete();Debug.Log($"result = {result[0]}");
private void Update()if (handle.IsCompleted)handle.Complete();Debug.Log($"result = {result[0]}");
private void OnDestroy()if (result.IsCreated)result.Dispose();

在上面的完整 Demo 代码中,有一点是之前没有提到的,就是下面这两句:


result = new NativeArray(1, Allocator.Persistent);
result.Dispose();

这里大家可以很明显的注意到,NativeContainer 是需要显式管理内存的。关于这方面的内容我会在后面的 NativeContainer 章节继续跟大家聊。

好,到这里大家应该对 C# Job System 有了一个初步的了解。让我们来做一个小测验,看我们是否真的理解了上面的内容。

下面的代码,输出结果会是什么?


public class MyCounterJobBehaviour : MonoBehaviourpublic struct CounterJob : IJobpublic NativeArray numbers;public int result;
public void Execute()for (int i = 0; i < numbers.Length; i++)result += numbers[i];
// Start is called before the first frame updatevoid Start()var numCount = 10;NativeArray numbers = new NativeArray(numCount, Allocator.TempJob);
for (int i = 0; i < numCount; i++)numbers[i] = i + 1;
var jobData = new CounterJobnumbers = numbers,result = 0
var handle = jobData.Schedule();handle.Complete();Debug.Log($"result = {jobData.result}");numbers.Dispose();

答案是result = 0

这个结果跟你想的一样么?

让我们来思考一下为什么是这个结果。我们再来看回顾一下 Job 的特点

需要声明成 struct

struct 中的数据必须是 blittable 的或者是 NativeContainer

要实现 IJob 接口

这些限制条件其实都是为了一个目的,就是要把 C# 中的 Job 数据复制到 native 层,最终由 native job system 去执行 job 中的逻辑。想到这其实我们的答案也就显而易见了,Execute() 方法中修改的其实只是我们 CounterJob 的一个副本,并不是原始的 CounterJob。因此当我们需要从 Job 中获得计算结果的时候,我们需要使用 NativeContainer,否则会得到不正确的结果。下面是正确的写法:


using Unity.Collections;using Unity.Jobs;using UnityEngine;
public class CounterJobBehaviour : MonoBehaviourpublic struct CounterJob : IJobpublic NativeArray numbers;public NativeArray result;
public void Execute()var tmp = 0;for (int i = 0; i < numbers.Length; i++)tmp += numbers[i];
result[0] = tmp;
void Start()var numCount = 10;NativeArray numbers = new NativeArray(numCount, Allocator.TempJob);var result = new NativeArray(1, Allocator.TempJob);
for (int i = 0; i < numCount; i++)numbers[i] = i + 1;
var jobData = new CounterJobnumbers = numbers,result = result
var handle = jobData.Schedule();handle.Complete();
Debug.Log($"result = {result[0]}");
result.Dispose();numbers.Dispose();

到这里我们就已经把 C# Job System 以及 IJob 大概了解了一下,相信大家应该已经注意到了,IJob 只能跑在单一工作(Worker)线程上,如果想要利用全部的工作(Worker)线程就需要用到我们下一节要介绍的另外一个接口了,那就是 IJobFor。

好,以上就是本节所有的内容了,下一节我们讲继续讨论 Job 的另一种形式:IJobFor。

感谢大家的耐心阅读

Unity 官方微信

第一时间了解Unity引擎动向,学习最新开发技巧

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
开国上将黄永胜,被判17年,出狱后分三套房子并告诉他五个安排

开国上将黄永胜,被判17年,出狱后分三套房子并告诉他五个安排

莫地方
2026-05-06 00:25:03
李凯尔悼念克拉克:我的心都碎了,我太爱你了兄弟

李凯尔悼念克拉克:我的心都碎了,我太爱你了兄弟

懂球帝
2026-05-13 09:08:07
退休党员别再乱交党费了!2026标准已明确,不少人白交多年冤枉钱

退休党员别再乱交党费了!2026标准已明确,不少人白交多年冤枉钱

笑熬浆糊111
2026-05-13 00:05:16
贾跃亭突然杀回来了

贾跃亭突然杀回来了

新行情
2026-05-12 14:09:08
“摸奶子”再惹争议,OPPO的流量反噬开始了

“摸奶子”再惹争议,OPPO的流量反噬开始了

品牌头版
2026-05-13 10:18:15
太平军攻南京有多惨烈?将军祥厚及五千旗兵全部被杀,满人被屠尽

太平军攻南京有多惨烈?将军祥厚及五千旗兵全部被杀,满人被屠尽

老范谈史
2026-05-11 19:45:11
水谷隼彻底揭穿张本宇一家在日本受尊重的谎言!

水谷隼彻底揭穿张本宇一家在日本受尊重的谎言!

生活新鲜市
2026-05-13 02:38:57
1-1!C罗摇头叹息,胜利遭98分钟压哨绝平,新月重燃夺冠希望

1-1!C罗摇头叹息,胜利遭98分钟压哨绝平,新月重燃夺冠希望

我的护球最独特
2026-05-13 04:11:44
女演员千万别整容,看央视《主角》观众对秦海璐的评价,就懂了

女演员千万别整容,看央视《主角》观众对秦海璐的评价,就懂了

陈述影视
2026-05-11 23:58:30
美国对中国统一下达新结论:大陆只要按兵不动,越晚统一代价越小

美国对中国统一下达新结论:大陆只要按兵不动,越晚统一代价越小

华史谈
2026-05-13 08:49:26
今年俄罗斯胜利日阅兵,为何唯独朝鲜派兵参加?中国怎么没派

今年俄罗斯胜利日阅兵,为何唯独朝鲜派兵参加?中国怎么没派

刘振起观点
2026-05-10 16:05:00
亚运会名单公布!孙颖莎领衔,陈幸同意外落选,陈熠入选引争议

亚运会名单公布!孙颖莎领衔,陈幸同意外落选,陈熠入选引争议

体育就你秀
2026-05-13 09:48:17
“扶弟魔”姐姐十年买房又给钱,却被弟弟一怒砍杀:钱给的不够花

“扶弟魔”姐姐十年买房又给钱,却被弟弟一怒砍杀:钱给的不够花

莫地方
2026-05-13 00:40:03
上海大学通报“院长苏某某论文被举报数据造假”:已成立调查组,启动调查程序 ,将根据调查情况严肃认真处理

上海大学通报“院长苏某某论文被举报数据造假”:已成立调查组,启动调查程序 ,将根据调查情况严肃认真处理

鲁中晨报
2026-05-12 16:54:06
要打奉陪到底,中方当面插旗,沉默72小时后,日本在境外发射导弹

要打奉陪到底,中方当面插旗,沉默72小时后,日本在境外发射导弹

华史谈
2026-05-13 08:56:11
“好豪迈的洛丽塔”,165cm未成年女儿穿搭火了,家长尴尬不敢认

“好豪迈的洛丽塔”,165cm未成年女儿穿搭火了,家长尴尬不敢认

妍妍教育日记
2026-05-12 18:46:53
5月13日,人社部、财政部关于2026年调整养老金通知下发了吗?

5月13日,人社部、财政部关于2026年调整养老金通知下发了吗?

小彬说事
2026-05-13 11:39:24
百亿影帝黄渤陪发小土耳其穷游:睡机场、日花150,真心最难得

百亿影帝黄渤陪发小土耳其穷游:睡机场、日花150,真心最难得

行者聊官
2026-05-12 10:55:44
天价转会费+冲金球!阿尔瓦雷斯有望以1.5亿欧空降大巴黎?

天价转会费+冲金球!阿尔瓦雷斯有望以1.5亿欧空降大巴黎?

田先生篮球
2026-05-12 22:10:29
卡塞米罗:我防守梅西时尽量不说话、不推搡,就怕激怒他

卡塞米罗:我防守梅西时尽量不说话、不推搡,就怕激怒他

懂球帝
2026-05-12 22:31:06
2026-05-13 12:43:00
Unity incentive-icons
Unity
Unity中国官方帐户
2466文章数 6732关注度
往期回顾 全部

科技要闻

谷歌剧透安卓重大升级 Gemini深度集成底层

头条要闻

特朗普访华随行名单:夫人缺席 次子夫妇、鲁比奥随行

头条要闻

特朗普访华随行名单:夫人缺席 次子夫妇、鲁比奥随行

体育要闻

14年半,74万,何冰娇没选那条更安稳的路

娱乐要闻

巩俐用中文宣布戛纳开幕,彰显国际地位

财经要闻

深圳夫妻囤芯片,身家飙涨320亿

汽车要闻

吉利银河“TT”申报图曝光 电动尾翼+激光雷达

态度原创

家居
旅游
时尚
亲子
数码

家居要闻

极简主义下的居住场域与空间

旅游要闻

金寨天堂寨:光影绘非遗 夜游启新篇

没八卦、纯素人、不惊艳,可她赢麻了

亲子要闻

闲置的“母婴用品”不要扔!竟然还有大用,帮你怒省几千元!

数码要闻

上游不优化我自己来!五年老卡RX 6800 XT内核魔改:MoE速度暴增至1770t/s

无障碍浏览 进入关怀版