
本文共 2558 字,大约阅读时间需要 8 分钟。
IJobParallelFor 的作用原理解:
IJob 一次只能执行单独的任务,如果需要反复执行某个操作多次,就功能上需要使用 ParallelFor 的功能。ParallelFor 却允许将任务拆分成多个并行运行的子任务,每次只处理数据源的一个独立部分。
ParallelFor jobs 通常使用 NativeArray 作为数据源,并能分配执行任务到多个 CPU 核心上。每个 job 都只负责处理完整数据的一个子集。当调用 Execute 方法时,框架会自动为数据源中的每个项目调用一次。
需要手动指定执行次数,通常直接取 NativeArray 的长度作为 executors 的数量,每个 executor 处理一个数据项。一个 job 在执行过程中,如果某个批处理提前完成,就会从其他 job 中拿取剩余的批处理继续执行。
关于粒度问题:
任务粒度太细会导致频繁的新 task 创建开销增加。而粒度过粗又会使 singlethreaded 的负载压力增大。一般来说,应从最小粒度1开始逐步增加,直到性能达到顶峰为止。
注意事项:
避免在 job 中访问 static 数据。因为 static 数据可能被多个 job 共享,会导致竞态条件。
Explicitly Flush scheduled batches。如果不调用 JobHandle.Complete(),调度逻辑将会被挂起等待 batch 执行结果完成才能继续。
不要试图直接修改 NativeContainer 的内容。如NativeArray[0]++ 这样的操作必须通过 Framework 提供的 API 执行,否则可能导致内存泄漏或逻辑错误。
在主线程中使用 Schedule 和 Complete 函数。不要在 job 依赖关系中使用前 job 中手动 schedule 后 job。
调用 Schedule 和 Complete 必须在正确的时机进行。Schedule 要在数据填充完毕后立即调用,Complete 则只在获取结果时才调用。
配合正确的使用 Schedule 和 Complete 方法。Schedule 方法实现了 «fire and forget» 模式,一旦调用就立即执行任务,无需等待结果。而 Complete 方法则是只在需要访问结果的时候使用,确保数据已经计算完成。
尽可能用读-only 对应 NativeArray。要是确认只需要读取数据的话,可以在初始化时标记为 read-only,这样可以提高性能。
不要在 Job 中使用托管内存分配。Job 内部的代码应该都避免使用 new 语句或者 GCpravітиve allocate。如果需要,应尽量使用 不可变的数据结构。
代码示例优化:
using System.Collections;using System.Collections.Generic;using Unity.Collections;using Unity.Jobs;using UnityEngine;using UnityEditor;public class TestJobParallelFor_1 : MonoBehaviour{ public struct MyParallelJob : IJobParallelFor { public NativeArraya; public NativeArray b; public NativeArray result; public void Execute(int index) { result[index] = a[index] + b[index]; } } // 调度并执行并行任务 void ScheduleParallelJob() { NativeArray a = new NativeArray (10, Allocator.TempJob); NativeArray b = new NativeArray (10, Allocator.TempJob); NativeArray result = new NativeArray (10, Allocator.TempJob); for (int i = 0; i < 10; i++) { a[i] = i * 0.3f; b[i] = i * 0.5f; } var jobData = new MyParallelJob(); jobData.a = a; jobData.b = b; jobData.result = result; // 执行并行任务 var handle = jobData.Schedule(10, 1); // 等待任务完成 handle.Complete(); // 检查结果 for (int i = 0; i < 10; i++) { Debug.LogError("Result at index " + i + ": " + result[i]); } // 配态 a.Dispose(); b.Dispose(); result.Dispose(); } // 在每帧更新时触发任务调度 private void Update() { ScheduleParallelJob(); } }
需要注意的关键点总结:
发表评论
最新留言
关于作者
