Unity Job系统详解原理和基础应用处理大量物体位置
概述
该脚本使用 Unity Job System 和 Burst Compiler 高效管理大量剑对象的位移计算与坐标更新。通过双缓冲技术实现无锁并行计算,适用于需要高性能批量处理Transform的场景。
核心类 SwordManager
成员变量
| 变量名 | 类型 | 说明 |
|---|---|---|
swordPrefab | GameObject | 剑对象预制体 |
_deltaPositions | NativeArray<float3> | 每帧位移增量数据 (临时内存分配) |
_positionsBufferA/B | NativeArray<float3> | 双缓冲位置数据 (持久化内存分配) |
_swordTransforms | TransformAccessArray | 批量访问Transform的容器 |
_useBufferA | bool | 双缓冲切换标志 |
作业系统实现
1. 位移计算作业 Vector3AddPositionsJob
[BurstCompile(FloatMode = FloatMode.Fast)]
struct Vector3AddPositionsJob : IJobParallelFor
{[ReadOnly] public NativeArray<float3> lastPositions; // 上一帧位置[ReadOnly] public NativeArray<float3> deltaPositions; // 位移增量[WriteOnly] public NativeArray<float3> currentPositions;// 计算结果public void Execute(int index) => currentPositions[index] = lastPositions[index] + deltaPositions[index];
}
- 功能:并行计算每个剑的新位置
- 优化:使用
BurstCompile加速数学运算,FloatMode.Fast启用快速浮点模式
2. Transform更新作业 UpdateTransformsJob
[BurstCompile]
struct UpdateTransformsJob : IJobParallelForTransform
{[ReadOnly] public NativeArray<float3> targetPositions;public void Execute(int index, TransformAccess transform) => transform.position = targetPositions[index];
}
- 特性:直接修改Unity Transform组件
- 优势:避免主线程的GameObject开销
主要方法详解
1. 初始化 Start()
// 创建1000个剑对象
List<Transform> transforms = new List<Transform>();
for (int i = 0; i < 1000; i++) {Instantiate(swordPrefab, randomPosition);
}// 初始化双缓冲
_positionsBufferA = new NativeArray<float3>(count, Allocator.Persistent);
_positionsBufferB = new NativeArray<float3>(count, Allocator.Persistent);
2. 每帧更新 Update()
if (Input.GetKeyDown(KeyCode.Space))
{// 分配临时位移数据_deltaPositions = new NativeArray<float3>(..., Allocator.TempJob);// 调度位移计算作业var positionJob = new Vector3AddPositionsJob {lastPositions = _useBufferA ? bufferA : bufferB,currentPositions = _useBufferA ? bufferB : bufferA};_positionJobHandle = positionJob.Schedule(count, GetOptimalBatchSize());// 调度Transform更新作业var transformJob = new UpdateTransformsJob {targetPositions = _useBufferA ? bufferB : bufferA};_transformJobHandle = transformJob.Schedule(_swordTransforms, _positionJobHandle);_useBufferA = !_useBufferA; // 切换缓冲区
}
3. 批次优化 GetOptimalBatchSize()
int GetOptimalBatchSize() => Mathf.Max(32, totalCount / (SystemInfo.processorCount * 4));
- 算法:根据CPU核心数动态调整批次
- 目标:平衡线程开销与并行效率
内存管理策略
-
双缓冲机制
- 交替读写避免数据竞争
- Buffer A/B 使用
Allocator.Persistent
-
临时数据
_deltaPositions使用Allocator.TempJob- 在Job完成后通过
Dispose()释放
-
销毁时清理
void OnDestroy() {JobHandle.Complete(); // 确保作业完成_swordTransforms.Dispose();_positionsBufferA/B.Dispose(); }
性能优化点
-
Burst编译加速
- 数学运算编译为高效Native代码
FloatMode.Fast牺牲精度换取速度
-
Transform批量访问
- 使用
TransformAccessArray减少API调用开销
- 使用
-
数据布局
- 结构体数据连续内存存储
- 避免CPU缓存失效
典型工作流程
注意事项
-
线程安全
- 确保Job完成前不修改NativeArray数据
- 使用
JobHandle.Complete()同步
-
内存泄漏防范
- 严格匹配
Allocator与Dispose() - 在
OnDestroy中释放持久化内存
- 严格匹配
-
移动端适配
- 测试不同处理器核心数的批次表现
- 调整
GetOptimalBatchSize除数因子
-
Burst兼容性
- 避免在Job中使用非Burst兼容代码
- 注意
Managed类型的使用限制
相关文章:
Unity Job系统详解原理和基础应用处理大量物体位置
概述 该脚本使用 Unity Job System 和 Burst Compiler 高效管理大量剑对象的位移计算与坐标更新。通过双缓冲技术实现无锁并行计算,适用于需要高性能批量处理Transform的场景。 核心类 SwordManager 成员变量 变量名类型说明swordPrefabGameObject剑对象预制体_d…...
高效编程指南:PyCharm与DeepSeek的完美结合
DeepSeek接入Pycharm 前几天DeepSeek的充值窗口又悄悄的开放了,这也就意味着我们又可以丝滑的使用DeepSeek的API进行各种辅助性工作了。本文我们来聊聊如何在代码编辑器中使用DeepSeek自动生成代码。 注:本文适用于所有的JetBrains开发工具,…...
Facebook 的隐私保护数据存储方案研究
Facebook 的隐私保护数据存储方案研究 在这个信息爆炸的时代,数据隐私保护已成为公众关注的热点。Facebook,作为全球最大的社交媒体平台之一,承载着海量用户数据,其隐私保护措施和数据存储方案对于维护用户隐私至关重要。本文将深…...
c#面试题整理
1.如何保持数据库的完整性,一致性 最好的方法:数据库约束(check,unique,主键,外键,默认,非空) 其次是:用触发器 最后:才是自己些业务逻辑,这个效率低 2.事…...
车载以太网测试-4车载以太网如何进行通信的?
1 摘要 车载以太网的数据传输与接收遵循分层网络架构(如OSI模型或TCP/IP模型),从应用层到物理层需要逐层封装与解封装。本文将对车载以太网的数据传输流程进行介绍。 2 以太网通信过程(封装与解封装) 2.1 发送端流程…...
R软件线性模型与lmer混合效应模型对生态学龙类智力测试数据层级结构应用
全文链接:https://tecdat.cn/?p40925 在生态与生物学研究中,数据常呈现复杂结构特征。例如不同种群、采样点或时间序列的观测数据间往往存在相关性(点击文末“阅读原文”获取完整代码、数据、文档)。 传统线性模型在处理这类非独…...
WIFI ESP8266以及基础功能介绍
芯片一旦烧写了程序就不可以使用AT指令集,需要重新刷回AT指令库才可以使用 wifi的通信频段是2.4G免费频段。 AT指令 AT(attention)command set.AT指令集或命令集,一般称为AT指令 海斯命令集:Hayes command set 默认…...
HarmonyOS ArkTS声明式UI开发实战教程
引言:为何选择ArkTS? 在HarmonyOS生态快速发展的当下,ArkTS作为新一代声明式UI开发框架,正在引发移动应用开发范式的变革。笔者曾在多个跨平台框架开发中经历过"命令式编程之痛",直到接触ArkTS后才发现&…...
FPGA之USB通信实战:基于FX2芯片的Slave FIFO回环测试详解
FPGA之Usb数据传输 Usb 通信 你也许会有疑问,明明有这么多通信方式和数据传输(SPI、I2C、UART、以太网)为什么偏偏使用USB呢? 原因有很多,如下: 1. 高速数据传输能力 高带宽:USB接口提供了较高的数据传…...
【MySQL_03】数据库基本--核心概念
文章目录 一、数据库基础1.1 数据库基础定义1.2 数据库分类与典型产品1.3 数据库模型1.4 数据库层次结构1.5 数据库核心机制1.6 数据表和视图1.61 数据表(Table)1.62 视图(View) 1.7 键类型1.8 MySQL数据类型1.9 数据库范式化 二、…...
神经网络|(十四)|霍普菲尔德神经网络-Hebbian训练
【1】引言 前序学习进程中,除了对基本的神经网络知识进行了学习,还掌握了SOM神经网络原理,文章链接包括且不限于: 神经网络|(十一)|神经元和神经网络-CSDN博客 神经网络|(十二)|常见激活函数-CSDN博客 神经网络|(十三)|SOM神经…...
【JAVA架构师成长之路】【Redis】第13集:Redis缓存击穿原理、规避、解决方案
30分钟自学教程:Redis缓存击穿原理与解决方案 目标 理解缓存击穿的定义及核心原因。掌握互斥锁、逻辑过期时间等预防技术。能够通过代码实现高并发场景下的缓存保护。学会熔断降级、热点探测等应急方案。 教程内容 0~2分钟:缓存击穿的定义与典型场景 …...
preloaded-classes裁剪
系统预加载了哪些class类?system/etc/preloaded-classes 修改源代码? frameworks\base\config\preloaded-classes 默认位置,如果改了不生效,可能有其它模块的mk文件指定了preloaded-classes覆盖了framework模块,例如…...
爬虫案例五多进程与多线程爬取斗图网
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、多进程与多线程爬取斗图网总结 前言 提示:这里可以添加本文要记录的大概内容: 爬取斗图网 提示:以下是本篇文章正文内…...
Redis的CPU高达90%时如何处理
Redis的CPU高达90%时如何处理 1. 分析和优化2. 扩展和分片3. 缓存策略调整4. 资源提升5. 负载均衡6. 进程调整7. 代码层面改进8. 其他 当Redis的CPU使用率高达90%时,说明Redis服务器可能处于过载状态,这可能会导致响应时间变长甚至服务中断。要处理这种…...
计算机视觉之dlib人脸关键点绘制及微笑测试
dlib人脸关键点绘制及微笑测试 目录 dlib人脸关键点绘制及微笑测试1 dlib人脸关键点1.1 dlib1.2 人脸关键点检测1.3 检测模型1.4 凸包1.5 笑容检测1.6 函数 2 人脸检测代码2.1 关键点绘制2.2 关键点连线2.3 微笑检测 1 dlib人脸关键点 1.1 dlib dlib 是一个强大的机器学习库&a…...
FPGA时序约束的几种方法
一,时钟约束 时钟约束是最基本的一个约束,因为FPGA工具是不知道你要跑多高的频率的,你必要要告诉工具你要跑的时钟频率。时钟约束也就是经常看到的Fmax,因为Fmax是针对“最差劲路径”,也就是说,如果该“最差劲路径”得到好成绩,那些不是最差劲的路径的成绩当然比…...
【0013】Python数据类型-列表类型详解
如果你觉得我的文章写的不错,请关注我哟,请点赞、评论,收藏此文章,谢谢! 本文内容体系结构如下: Python列表,作为编程中的基础数据结构,扮演着至关重要的角色。它不仅能够存储一系…...
10.RabbitMQ集群
十、集群与高可用 RabbitMQ 的集群分两种模式,一种是默认集群模式,一种是镜像集群模式; 在RabbitMQ集群中所有的节点(一个节点就是一个RabbitMQ的broker服务器) 被归为两类:一类是磁盘节点,一类是内存节点; 磁盘节点会把集群的所有信息(比如交换机、绑…...
Web网页开发——水果忍者
1.介绍 复刻经典小游戏——水果忍者 2.预览 3.代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title&…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...
Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...
