1.JobSystem简介
2.Job简介
3.Job实例
4.Job原理
1.JobSystem简介
1).为什么需要JobSystem
a.在Unity中, 游戏逻辑通常在主线程(Main Thread)上运行; 随着游戏越来越复杂, 需要处理的计算量越来越大
比如: 成千上万的物体移动, 物理模拟, AI决策等, 单线程就可能成为性能瓶颈
b.多线程可以解决这个问题, 但多线程编程复杂, 容易出错(比如: 竞争条件, 数据不一致, 死锁等); Unity JobSystem就
是为了"让开发者能够安全, 方便地使用多线程而设计的"
2).什么是JobSystem
JobSystem是Unity的一个"多线程系统", 它允许开发者编写简单, 独立的任务(Jobs), 这些任务可以并行, 从而充分利用多
核CPU
3).核心概念
a.Job: 一个小的任务单元, 比如计算一个物体的移动;Unity中, Job是一个实现了IJob, IJobParallelFor等接口的struct
b.主线程调度: 可以在主线程安排Job的执行, 然后等待Job完成
c.依赖关系: Job之间可以有依赖关系, 比如Job B需要等Job A完成才能开始
d.安全性: Job System使用线程安全的方式访问数据, 避免竞争条件
e.它通过拷贝数据或使用NativeContainer(如NativeArray)来共享数据
拷贝数据(值类型结构), 原理: "Job收到的是数据的独立副本, 修改不会影响原始数据"


NativeContainer(原生容器), 原理: "Job和主线程共享同一块内存"

NativeArray示例



2.Job
1).Job(任务)
一个独立的工作单元, 必须是struct(结构体)

2).Job类型

3).NativeContainer(原生容器)
Job System不允许直接访问托管对象(比如普通的数组、List), 因为这样会有线程安全问题, 必须使用下面的容器

创建NativeContainer需要指定分配器
a.Allocator.Temp: 最快, 但生命周期只有一帧, 且只能在主线程使用
b.Allocator.TempJob: 较慢, 但生命周期为4帧, 可以在Job中使用, 用于小型短期数据
c.Allocator.Persistent: 最慢, 但可以长期存在, 用于大型长期数据
注: "通常Job中使用Allocator.TempJob"
NativeContainer的读写权限
a.[ReadOnly]: 只读, 允许多个Job同时读取
b.[WriteOnly]: 只写
c.默认: 可读写, 但同一时间只能有一个Job写
4).JobHandle(任务句柄)

5).注意事项
a.不要在Job中访问静态变量: 这会导致竞争条件

b.不要在Job中调用Unity的API: 大部分Unity API都不是线程安全的
c.及时释放NativeContainer: 否则会导致内存泄漏
d.合理划分批次: 对于IJobParallelFor, 批次大小影响并行效率, 需要根据任务大小调整
3.Job实例
1).基础任务

2).并行任务

job.Schedule(任务的总数, 批次的数目), 将任务分批, 这些批次会被分配到多个工作线程上执行; 每个线程一次处理一个
批次, 然后获取下一个可用批次, 直到所有批次完成("推荐批次的数目 32-128")
Execute中的index参数表示"当前工作线程正在处理的数据索引", 对于批次而言
4.Job原理
Job System使用线程池(Thread Pool)
a).线程池管理
Unity的Job System内部维护一个线程池, 当你调度一个Job时, 它会被添加到作业队列中, 线程池中的工作线程会从队列中
取出作业并执行
b).工作线程
线程池中的工作线程在程序启动时创建, 这些线程在Job System的整个生命周期内存在, 不会频繁创建和销毁, 避免了线程
创建的开销
c).主线程和Worker线程
- 主线程: 运行Unity的游戏循环(Update、渲染等)
- Worker线程: 线程池中的线程, 用于执行Job
d).Job调度过程

e).并行Job(IJobParallelFor)
对于并行Job, Job System会将工作分解为多个批次(batch), 每个批次由一个Worker线程处理; 多个Worker线程可以同时处
理同一个Job的不同批次

2566

被折叠的 条评论
为什么被折叠?



