多线程开发,数据加载与计算也是在主线程基础上分前后顺序的,这里就要了解Job间的依赖关系。
JobHandle和依赖关系:
当你调用Schedule方法时会返回一个JobHandle。你可以在代码中使用JobHandle作为其他jobs的依赖关系。
组合依赖关系:
如果一个job有多个依赖项,你可以使用JobHandle.CombineDependencies方法来合并他们。CombineDependencies允许你将他们传递给Schedule方法。
在主线程中等待jobs结束:
使用JobHandle来让你的代码在主线程等待知道你的job执行完毕。为了做到这样,需要在JobHandle上调用Complete方法。这样的话,你就确定主线程可以安全访问job之前使用的NativeContainer。
便捷的扩展:
一个ParallelForTransform job是另一个类型的ParallelFor job;它是专门为了Transforms上的操作设计的。
案例七:IJobParallelForTransform在Job设定Transform信息(Scne8)
脚本:JobParallelForTransformTest
using UnityEngine;
using Unity.Jobs;
using Unity.Entities;
using Unity.Collections;
using UnityEngine.Jobs;
public class JobParallelForTransformTest : MonoBehaviour
{
struct VelocityJob : IJobParallelFor
{
public NativeArray<Vector3> positions;
public NativeArray<Vector3> velocitys;
public float delaTime;
// 并行化 让一个线程做数组的一部分处理
public void Execute(int index)
{
positions[index] = positions[index] + velocitys[index] * delaTime;
}
}
// 注意这个 job扩展是定义在 UnityEngine.Jobs命名空间下
struct ApplyTransform : IJobParallelForTransform
{
public NativeArray<Vector3> positions;
public void Execute(int index, TransformAccess transform)
{
transform.position = positions[index];
}
}
public int gameCount = 300;
public GameObject prefab;
public GameObject[] gameObjs;
private TransformAccessArray tranAccessArray; // 类似 nativeContainer 也是需要释放
void Start()
{
gameObjs = new GameObject[gameCount];
tranAccessArray = new TransformAccessArray(gameCount); // 注意 这种类型数组必须将capacity主动填上 不能像list一样直接new便可以add
for (int i = 0; i < gameCount; i++)
{
gameObjs[i] = Instantiate<GameObject>(prefab);
gameObjs[i].transform.position = UnityEngine.Random.insideUnitSphere * 40;
tranAccessArray.Add(gameObjs[i].transform);
}
}
void Update()
{
// 1.准备数据
NativeArray<Vector3> tmpPositions = new NativeArray<Vector3>(gameCount, Allocator.TempJob);
NativeArray<Vector3> tmpVelocitys = new NativeArray<Vector3>(gameCount, Allocator.TempJob);
for (int i = 0; i < gameCount; i++)
{
tmpVelocitys[i] = new Vector3(0, 1, 0);
//tmpPositions[i] = tmpPositions[i] + tmpVelocitys[i] * Time.deltaTime;
tmpPositions[i] = gameObjs[i].transform.position;
}
VelocityJob job = new VelocityJob()
{
positions = tmpPositions,
delaTime = Time.deltaTime,
velocitys = tmpVelocitys
};
//依赖按照速度计算的到的位置数组
ApplyTransform applyTransform = new ApplyTransform()
{
positions = tmpPositions
};
// 2.执行
//信号量 主线程如何知道子线程执行完毕 gameCount 指定总共子线程执行数据数量 10:每个子线程以下处理多少次
JobHandle jobHandle = job.Schedule(gameCount, 10);
JobHandle tranHandle = applyTransform.Schedule(tranAccessArray, jobHandle);
// 3.同步
jobHandle.Complete();
tranHandle.Complete();
//4。更新位置
//for (int i = 0; i < gameCount; i++)
//{
// gameObjs[i].transform.position = tmpPositions[i];
//}
tmpPositions.Dispose();
tmpVelocitys.Dispose();
}
private void OnDestroy()
{
this.tranAccessArray.Dispose();
}
}
使用传统c#并不能直接跨线程访问Unity的UI,Unity便自己扩展了功能,如下图让程序方便在job中修改Transform信息(注意该结构体是在UnityEngine的核心模块里):
远程项目仓库(github):https://github.com/h1031464180/UnityECS