Unity JobSystem 使用教程
深入讲解 Unity C# JobSystem 的核心概念、常见 Job 类型、依赖管理、Burst 编译器加速及性能调优,助你多核释放潜能。
适用版本:Unity 2022.3 LTS+,示例项目启用 Entities 1.2 & Burst 1.8。旧版 JobSystem API 亦可参考。
目录
- 前言
- 为何要用 JobSystem
- 核心概念速览
- 创建第一个 Job
- 常用 Job 接口
- 依赖与调度
- Burst 编译器
- Native 容器与内存安全
- 调试与 Profiler
- 案例:并行地形高度计算
- 常见坑与最佳实践
- 结语
前言
在现代移动与主机硬件上,核心数稳步提升,而主线程瓶颈成为性能硬伤。Unity C# JobSystem 通过易用的 API,把密集计算拆分到工作线程,实现 真·多核利用。本文将带你从入门到进阶,掌握 Job 编写、调度与优化。
为何要用 JobSystem
- 并行计算:充分利用 CPU 多核。
- 主线程减负:将耗时逻辑移出
Update()
,提升帧率。 - 数据导向:与 ECS(Entities)无缝协作,享受线性内存布局。
JobSystem ≠ 传统 C#
Thread
,它由 Unity 调度器管理线程池,更安全高效。
核心概念速览
名称 | 作用 |
---|---|
IJob |
单任务,适合少量计算 |
IJobParallelFor |
数据分片并行 |
IJobChunk |
与 ECS Chunk 同步 |
JobHandle |
调度后返回,管理依赖 |
Schedule() |
异步执行 |
ScheduleParallel() |
分片并行 |
Complete() |
阻塞主线程等待执行完 |
创建第一个 Job
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
[BurstCompile] // 开启 Burst 优化
public struct SqrtJob : IJob
{
public NativeArray<float> values;
public void Execute()
{
for (int i = 0; i < values.Length; i++)
values[i] = Mathf.Sqrt(values[i]);
}
}
public class JobExample : MonoBehaviour
{
void Start()
{
var data = new NativeArray<float>(100, Allocator.TempJob);
for (int i = 0; i < data.Length; i++) data[i] = i;
var job = new SqrtJob { values = data };
JobHandle handle = job.Schedule(); // 调度
handle.Complete(); // 等待完成
Debug.Log($"Result[10] = {data[10]}"); // √10
data.Dispose();
}
}
常用 Job 接口
接口 | 适用场景 |
---|---|
IJobParallelFor |
大量元素独立计算(物理、AI 感知) |
IJobParallelForTransform |
批量更新 Transform |
IJobChunk |
在 ECS Chunk 粒度并行 |
IJobEntityBatch |
Entities.ForEach 的底层实现 |
示例 —— 并行向量归一化:
[BurstCompile]
public struct NormalizeJob : IJobParallelFor
{
public NativeArray<float3> vectors;
public void Execute(int index) => vectors[index] = math.normalize(vectors[index]);
}
依赖与调度
JobHandle h1 = job1.Schedule();
JobHandle h2 = job2.Schedule(h1); // h2 依赖 h1
JobHandle h3 = JobHandle.CombineDependencies(h1, h2);
h3.Complete(); // 等待全部完成
- 依赖链:避免数据竞争。
- BatchCount:
ScheduleParallel
第 3 参数决定切片大小。
Burst 编译器
- 向量化:生成 SIMD 指令(SSE4/NEON/AVX2)。
- 跨平台:一次编写,多架构优化。
- 调试:
Jobs → Burst → Enable Safety Checks
可查看潜在越界。
[BurstCompile(FloatPrecision.Standard, FloatMode.Fast)]
在 PlayerSettings→Other→ScriptingBackend 使用 IL2CPP 与 Mono 都可启用 Burst。
Native 容器与内存安全
容器 | 线程安全 | 特点 |
---|---|---|
NativeArray<T> |
✔ | 线性存储 |
NativeList<T> |
✔ | 动态扩容 |
NativeQueue<T> |
半 | Concurrent 结构体并行写 |
NativeHashMap<K,V> |
半 | 并行读/写分离 |
- 释放:
Dispose()
或Dispose(handle)
延迟销毁。 - 禁止在 Job 外访问正在执行的容器。
调试与 Profiler
- Profiler → Timeline → Jobs:查看 Job 排队与线程占用。
- Entity Debugger:ECS Job 状态。
- Burst Inspector:反汇编检查向量化效果。
- Unity 2023.2+:Job Dependencies 视图。
案例:并行地形高度计算
[BurstCompile]
public struct HeightJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float3> positions;
[WriteOnly] public NativeArray<float> heights;
public void Execute(int index)
{
float3 p = positions[index];
heights[index] = noise.cnoise(p * 0.1f);
}
}
// 调度
var pos = new NativeArray<float3>(vertexCount, Allocator.TempJob);
var hgt = new NativeArray<float>(vertexCount, Allocator.TempJob);
var job = new HeightJob { positions = pos, heights = hgt };
JobHandle handle = job.ScheduleParallel(vertexCount, 64, default);
handle.Complete();
// 后续生成 Mesh 高度...
结果:CPU 耗时从 18 ms → 2 ms(iPhone 13)。
常见坑与最佳实践
- 别在 Job 里分配托管内存(如
new List<T>()
)。 - 避免
Complete()
过度:会阻塞主线程。使用Dependency
合并等待点。 - 合理切片:元素 < 100 时串行更快。
- NativeList 并行写:需
NativeList<T>.ParallelWriter
。 - Burst 与 Unity.Mathematics:优先使用
math.*
,少用System.Math
。
结语
掌握 JobSystem,你就掌握了移动端与主机的多核钥匙。结合 ECS 与 Burst,可让 CPU 性能腾飞 5–20 倍。把本文示例融入项目,体验丝滑帧率吧!
附件 · 示例脚本列表
Jobs/SqrtJob.cs
Jobs/NormalizeJob.cs
Jobs/HeightJob.cs
需要完整工程?留言即可获取 GitHub 地址。
Last modified on 2025-06-09