为保证数据在多线程下的安全准确性,需要使用[NativeContainer]修饰的存储结构类来定义变量
NativeArray 数组
NativeHashMap 字典
NativeMultiHashMap 哈希字典
NativeQueue 队列
定义它们都有一个周期概念,常用如下3个:
Allocator.Temp 生命周期最短 速度最快 1帧内使用
Allocator.TempJob 周期速度中等 四帧内
Allocator.Persistent 周期最长 最慢 长久使用
API说明:
WithDeallocateOnJobCompletion(xxx) Job执行结束时自动销毁xxx
CompleteDependency() 阻塞线程
WithReadOnly(xxx) 将xxx设置为只读
WithNativeDisableContainerSafetyRestriction(xxx)
解除intArray的安全检测(例如超出索引范围检测)用户需保证安全操作数组
WithNativeDisableParallelForRestriction(xxx)
允许多个线程对intArray同时进行操作,控制不好可能会产生冲突
WithNativeDisableUnsafePtrRestriction(xxx)
允许您使用本机容器提供的不安全指针。不正确的指针使用可能导致应用程序中出现细微的错误、不稳定和崩溃)
WithStructuralChanges()
当前的lambda表达式在主线程执行,并且禁用Burst,让你可以在里面对entity进行架构的改变。不过,为了效率,尽量使用EntityCommandBuffer,而不是使用这个。
EntityCommandBuffer(实体指令缓存器)
AddComponent(entity, component) 追加一个针对实体进行添加组件操作放入实体指令缓存器
Playback(EntityManager) 执行缓存器里所有指令
Dispose 销毁缓存器
Either assign the field to a local outside of the lambda expression and use that instead, or use .WithoutBurst() and .Run()
若发生如上报错,原因是ForEach里使用了成员变量,而且没有使用WithoutBurst().Run()去保证不使用Burst和保证在主线程执行,要么加上,要么不要使用成员变量,而是局部变量 且是TempJob修饰类型。
cs
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;
/// <summary>
/// 可操作主线程或多线程; ComponentSystem单线程 JobComponentSystem多线程
/// </summary>
public class MySystemBase : SystemBase
{
EntityQuery query;
//以下方法从上到下按顺序执行
protected override void OnCreate()
{
Debug.Log("OnCreate");
}
protected override void OnStartRunning()
{
Debug.Log("OnStartRunning");
}
protected override void OnUpdate()
{
Debug.Log("OnUpdate");
//WithDeallocateOnJobCompletion 自动销毁NativeArray
NativeArray<int> intArray = new NativeArray<int>(3, Allocator.TempJob);//列表
NativeHashMap<int, int> map = new NativeHashMap<int, int>(3, Allocator.TempJob);//类似字典
NativeMultiHashMap<int, int> mulMap = new NativeMultiHashMap<int, int>(3, Allocator.TempJob);//允许多个相同key
NativeQueue<int> queue = new NativeQueue<int>(Allocator.TempJob);//队列
//Allocator.Temp 生命周期最短 速度最快 1帧内使用
//Allocator.TempJob 周期速度中等 四帧内
//Allocator.Persistent 周期最长 最慢 长久使用
Entities.ForEach((ref Translation trans) =>
{
intArray[0] = 2;
map.TryAdd(1, 2);
if (!mulMap.ContainsKey(1))
{
mulMap.Add(1, 2);
}
if (queue.Count == 0)
{
queue.Enqueue(1);
}
}).WithDeallocateOnJobCompletion(intArray).ScheduleParallel();
Entities.ForEach((ref Translation trans) =>
{
intArray[0] = 2;
}).ScheduleParallel();
//阻塞线程 安全释放缓存
CompleteDependency();
intArray.Dispose();
//WithReadOnly 将变量设置为只读
Entities.ForEach((ref Translation trans) =>
{
intArray[0] = 2;
}).WithReadOnly(intArray).ScheduleParallel();
//WithNativeDisableContainerSafetyRestriction 解除intArray的安全检测(例如超出索引范围检测)用户需保证安全操作数组
Entities.ForEach((ref Translation trans) =>
{
intArray[0] = 2;
}).WithNativeDisableContainerSafetyRestriction(intArray).ScheduleParallel();
//WithNativeDisableParallelForRestriction 允许多个线程对intArray同时进行操作,控制不好可能会产生冲突
Entities.ForEach((ref Translation trans) =>
{
intArray[0] = 2;
}).WithNativeDisableParallelForRestriction(intArray).ScheduleParallel();
//WithNativeDisableUnsafePtrRestriction 允许您使用本机容器提供的不安全指针。不正确的指针使用可能导致应用程序中出现细微的错误、不稳定和崩溃)
unsafe
{
int* iPtr = (int*)intArray.GetUnsafePtr();
Entities.ForEach((ref Translation trans) =>
{
iPtr[0] = 2;
}).WithNativeDisableUnsafePtrRestriction(iPtr).ScheduleParallel();
}
//对筛选出的实体进行添加组件操作
//WithStructuralChanges 当前的lambda表达式在主线程执行,并且禁用Burst,让你可以在里面对entity进行架构的改变。不过,为了效率,尽量使用EntityCommandBuffer,而不是使用这个。
Entities.ForEach((Entity entity, ref Translation trans) =>
{
EntityManager.AddComponentData(entity, new PrintTestComponentData() { num = 1 });
}).WithStructuralChanges().WithoutBurst().Run();
//推荐用以下方式 效率高
EntityCommandBuffer commandBuffer = new EntityCommandBuffer(Allocator.TempJob);
Entities.ForEach((Entity entity, ref Translation trans) =>
{
commandBuffer.AddComponent(entity, new PrintTestComponentData() { num = 1 });
}).WithoutBurst().Run();
commandBuffer.Playback(EntityManager);
commandBuffer.Dispose();
}
protected override void OnStopRunning()
{
Debug.Log("OnStopRunning");
}
protected override void OnDestroy()
{
Debug.Log("OnDestroy");
}
}