【Unity3D】ECS入门学习(十)NativeContainer、EntityCommandBuffer、CompleteDependency

为保证数据在多线程下的安全准确性,需要使用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");
    }
}
相关推荐
RD_daoyi15 小时前
外链权重暴跌至13%,品牌提及反超传统链接——2026年不做Digital PR,你的独立站等于隐形
运维·网络·学习·机器学习·搜索引擎
chase。16 小时前
【学习笔记】PointWorld:迈向通用机器人操控的3D世界模型
笔记·学习·机器人
AOwhisky17 小时前
Python 学习笔记(第十三期)——运维自动化(下·前篇):远程命令执行——paramiko基础篇
运维·python·学习·云原生·自动化·运维开发·paramiko
前端世界17 小时前
MySQL 基础入门(学习第4天)——约束与 DML 操作详解
数据库·学习·mysql
dear_bi_MyOnly17 小时前
【SpringBoot配置文件】
java·spring boot·后端·学习·spring·java-ee·学习方法
AOwhisky17 小时前
Python 学习笔记(第十四期)——运维自动化(下·中篇):远程文件传输——paramiko进阶篇
运维·python·学习·云原生·自动化·文件传输·paramiko
math_hongfan17 小时前
鸿蒙Flutter setState机制深入理解
学习·flutter·华为·harmonyos·鸿蒙
旧物有情17 小时前
游戏开发常用架构 #MVP,MVC
游戏·unity·架构·mvc
其实防守也摸鱼17 小时前
补天SRC新手入门指南:从0到1的漏洞挖掘之路
网络·python·学习·安全·web安全·数据挖掘·挖洞
星恒随风18 小时前
C++ STL 栈详解:stack 的使用、经典题目与简单模拟实现
开发语言·数据结构·c++·笔记·学习