Unity C# Job System介绍(一)

Unity的C#JobSystem允许开发者编写多线程代码,以提高性能和续航,同时融入Unity原生JobSystem共享workerthreads,避免过多线程竞争CPU资源。本文解释了多线程和JobSystem的基本概念,以及它们如何在游戏开发中协同工作。

翻译自官方文档,原文地址 https://docs.unity3d.com/Manual/JobSystemOverview.html

C# Job System 总览

Unity的C# Job System使用户可以编写与Unity其他部件交互的多线程代码,同时让编写正确的代码变得更容易。

编写多线程代码可以提供更好的性能表现。这包括极大的提升提升和手机上更久的续航。

C# Job System的一个非常关键的方面是它可以融入Unity内部的原生Job System。这使得用户的代码可以和Unity共享worker threads。这种合作避免了创建更多线程,因为这可能会造成对于CPU资源的争抢。

关于更多的信息,可以观看演讲Unity at GDC - Job System & Entity Component System

什么是多线程?

原文地址 https://docs.unity3d.com/Manual/JobSystemMultithreading.html

在一个单线程的计算系统中,当输入指令的时候,结果会在同时计算产生。加载和运行程序的时间取决于你需要CPU处理的工作的数量。

多线程是一种编程技术,充分利用CPU的多个核心可以在同一时间处理多个不同线程的能力。任务或者指令会在同一时间执行,而不是一个接一个执行。

有一个线程会在程序开始的时候默认运行,被称为“主线程”。主线程创建新的线程来处理任务。这些新的线程会并发地执行,并在任务完成时向主线程同步自己的结果。

这种多线程的方法在你有几个需要较长时间运行的任务时表现良好。但是,游戏代码中通常包含很多需要同时执行的短指令。如果你为每一个指令都创建一个进程,你会因为拥有太多短生命周期的线程而失败。这会加剧CPU和操作系统处理能力的紧张。

线程生命周期的问题可能可以通过线程池的方式来解决。但是,即使你使用了线程池,你依然可能在同一时间拥有大量的活跃线程。CPU上运行更多的线程会导致彼此争抢CPU上的资源,这将会导致频繁的上下文切换(Context switching)。上下文切换是将正在执行的线程状态保存下来,然后执行另一个线程,随后再恢复到第一个线程并继续执行的过程。上下文切换会大量占用资源,所以需要尽可能避免需要用到它。

什么是Job System?

一个job system通过创建jobs而不是线程来管理多线程的代码。

一个job system管理运行在多个核心上的一组工人线程(worker threads)。通常一个逻辑CPU核心上会有一个工人线程,从而避免上下文切换(虽然可能会为操作系统或其他专有程序保留一些核心)。

一个job system会把jobs放到一个job队列中去执行。job system中的工人线程从job队列中取出内容并执行他们。一个job system会管理依赖性并确保jobs以正确的顺序被执行。

什么是一个Job?

一个job是小单位的工作,通常包含一个特定的任务。一个job接受参数并根据数据进行操作,接近于一个方法的工作方式。job可以是独立的,或者他们可以依赖于其他jobs完成后再执行。

什么是Job的关联性?

在复杂的系统中,像是游戏开发需要的系统,不太可能每一个job都是独立的。一个job通常会准备下一个job所需要的数据。jobs了解并支持这种依赖来确保可以正常工作。如果jobA依赖于jobB,那么job system会确保jobB执行完毕后才开始执行jobA。

Unity 的 **C# Job System** 是种用于优化性能的多线程任务处理系统,它允许开发者将计算任务分割为多个 **Job**(作业),并在多个 CPU 核心上并行执行。由于 Unity 引擎自动管理线程池和同步机制,开发者可以专注于任务逻辑的实现,而无需处理底层的线程管理[^2]。 ### 核心组件与概念 1. **Job**:Job个轻量级的任务,它可以在多个线程上并行执行。Job 需要实现 `IJob` 接口或其派生接口(如 `IJobParallelFor`、`IJobParallelForTransform`)。 2. **NativeContainer**:为了确保 Job 安全地访问数据,Unity 提供了 `NativeArray<T>`、`NativeList<T>` 等原生容器,这些容器支持跨线程访问且不会产生垃圾回收(GC)负担。 3. **JobHandle**:每个提交的 Job 都会返回个 `JobHandle` 对象,它用于跟踪 Job 的执行状态,并支持依赖链的构建,确保 Job 按照正确的顺序执行。 4. **Scheduling**:Job 的调度由 Unity 自动管理,开发者可以通过 `JobHandle` 来控制调度顺序,实现依赖关系。 ### 基本使用流程 以下是个使用 `IJobParallelFor` 的简单示例,展示如何在多个元素上并行执行操作: ```csharp using Unity.Burst; using Unity.Jobs; using Unity.Collections; using UnityEngine; public class JobExample : MonoBehaviour { void Start() { int length = 1000; NativeArray<float> values = new NativeArray<float>(length, Allocator.TempJob); // 定义Job var job = new MyJob { Values = values }; // 调度 Job JobHandle handle = job.Schedule(length, 64); // 64 为批处理大小 // 等待 Job 完成 handle.Complete(); // 读取结果 for (int i = 0; i < length; i++) { Debug.Log(values[i]); } values.Dispose(); // 释放原生容器 } [BurstCompile] struct MyJob : IJobParallelFor { public NativeArray<float> Values; public void Execute(int index) { Values[index] = Mathf.Sin(index * 0.1f); } } } ``` ### 最佳实践 1. **合理划分 Job 粒度**:Job 的粒度不宜过小,否则调度开销可能超过实际计算收益。建议将任务划分为多个中等大小的 Job,以充分利用 CPU 资源。 2. **使用 Burst 编译器**:通过 `[BurstCompile]` 属性可以显著提升 Job 的执行效率,Burst 将 C# 编译为高度优化的本地代码[^1]。 3. **避免主线程阻塞**:尽量避免频繁调用 `JobHandle.Complete()`,特别是在 Update 方法中。可以使用依赖链来异步处理多个 Job。 4. **使用 NativeContainer 管理数据**:确保所有在 Job 中访问的数据都封装在 `NativeArray`、`NativeList` 等容器中,以避免内存安全问题。 5. **控制调度频率**:对于频繁执行的小型任务,建议使用 `IJobParallelFor` 并设置合适的批处理大小(batch size),通常 32 到 1024 之间较为合适。 ### 多线程与依赖管理 Unity Job System 支持 Job 之间的依赖关系管理。例如: ```csharp JobHandle firstJobHandle = firstJob.Schedule(...); JobHandle secondJobHandle = secondJob.Schedule(..., firstJobHandle); secondJobHandle.Complete(); ``` 上述代码确保了 `secondJob` 在 `firstJob` 完成之后才开始执行。这种机制非常适用于流水线式的任务处理逻辑。 ### 性能调优建议 - **分析 Job 执行时间**:使用 Unity 的 Profiler 工具监控 Job 的执行时间,识别瓶颈。 - **减少主线程与 Job 之间的数据同步**:避免频繁地从主线程读取 Job 结果,尽可能在 Job 中完成数据处理。 - **合理使用 Allocator.TempJob**:该分配器专为 Job 设计,生命周期短,适合临时数据使用。 ### 常见问题与注意事项 - **GC 内存不能在 Job 中使用**:所有在 Job 中使用的数据结构必须为非托管类型或使用 `NativeContainer`。 - **避免竞态条件**:多个 Job 同时写入同数据会导致未定义行为,应使用适当的同步机制或设计无共享数据的 Job。 - **注意 Job 的执行顺序**:除非显式设置依赖关系,Job 的执行顺序是不确定的。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值