unity里 Burst的用法

using Unity.Burst;

using Unity.Collections;

using Unity.Jobs;

using Unity.Mathematics;

using UnityEngine;

public class UnitMoveSystem : MonoBehaviour

{

NativeArray positions;

NativeArray velocities;

Transform\[\] units; // 普通 C# 侧还是用这些

复制代码
void Update()
{
    // 1) 普通 C#:把场景数据填进原生数组(或上帧结果已在数组里)
    for (int i = 0; i < units.Length; i++)
        positions[i] = units[i].position;

    // 2) Burst Job:只做纯计算
    var job = new MoveJob
    {
        positions = positions,
        velocities = velocities,
        deltaTime = Time.deltaTime
    };
    JobHandle handle = job.Schedule(units.Length, 64);
    handle.Complete(); // 小项目先 Complete;大项目可延迟一帧再取

    // 3) 普通 C#:把结果写回 Unity 对象
    for (int i = 0; i < units.Length; i++)
        units[i].position = positions[i];
}

[BurstCompile]
struct MoveJob : IJobParallelFor
{
    public NativeArray<float3> positions;
    [ReadOnly] public NativeArray<float3> velocities;
    public float deltaTime;

    public void Execute(int i)
    {
        positions[i] += velocities[i] * deltaTime;
    }
}

}

项目里怎么落地(实操规则)

先用普通 C# 写对

功能稳定后,再找 Profiler 里 CPU 高的循环。

只抽"纯计算热点"进 Burst

例如:批量移动、距离排序、伤害结算的数值段、生成高度图。

不要把 UI、网络、Instantiate、直接碰 Transform 塞进 Job。

数据用原生容器

NativeArray、NativeList 等,并在合适时机 Dispose,避免泄漏。

什么规模值得上

情况 建议

几十个对象、逻辑不重

普通 C# 即可

成百上千、循环明显吃 CPU

Jobs + Burst

上万实体、要极致

再考虑 DOTS/ECS(仍是这套思想的强化版)

一句话工作流

Profiler 找到热循环 → 数据改成数组 → Job 里 Burst 算 → 主线程写回场景。

.为什么Burst代码会比普通的代码快/效率高.

1.burst有.自动向量化 SIMD的计算(数组型计算时很有效率),CPU 用宽一点的寄存器,一次装好几个 float同时运算。数组/连续内存,循环规整、依赖少,减少了内存切页。

2.Burst 限制你多用 struct、NativeArray,少用/不用 class、new 托管对象、随便装箱。这样就不会有托管环境里的额外成本,Burst 就变成了连续的数值内存 → 直接算 → 算完。而普通的类对象引用 → 托管检查 → 可能触发/牵扯 GC → 再算 普通的类跑在托管环境里的额外成本:对象头、引用检查,数组边界检查(更频繁/更难优化时),不能当纯数值那样随便重排指令,和 GC 相关的写屏障等。所以burst代码几乎没有 GC / 托管开销,算得更纯粹。

3.Burst 编成高度优化的原生码:普通 C# 脚本编译好在Mono/IL2CPP 托管执行,Burst 编译的代码编成原生机器码(类似 C/C++)。

Burst :受限 C# → Burst/LLVM → 直接生成原生机器码

普通 C# → IL → IL2CPP 转成 C++ → 再编成原生机器码

4.常配合 Jobs 多线程(这是另一层加速,严格说不属于 Burst 本身)

打包过程中 打进 APK 后

普通 C#(IL2CPP)

C# → 生成临时 C++ → 再编译

机器码(在 libil2cpp.so 等里)

Burst

受限 C# → LLVM → 生成原生码

机器码(常在 lib_burst_generated.so 一类库里)

普通 C#

class、普通数组、字符串 → 托管堆(GC)

Burst Job

NativeArray 等 → 原生内存(非 GC)

是不是原生内存就更快?

不是"原生"两个字本身自带加速度,而是原生这条路上通常更少拖后腿:

没有 GC 干扰(热路径不分配托管对象、不被回收打断)

数据更连续、更好缓存(结构体数组,不像一堆对象东一块西一块)

方便 Burst 做 SIMD/激进优化

少一层托管对象语义负担

如果只是读一个 float,原生和托管数组的理论带宽差不多;

真正拉开差距的,是上面这些在大批量热循环里的累积优势。

一句话: 普通 C# 多用托管堆,Burst 多用原生内存;更快主要是因为少 GC、更连续、更好优化,不是单纯"原生内存魔法加速"。

结构体数组为什么香

NativeArray 或 EnemyData\[\](EnemyData 是 struct)大致是这样排的:

敌1整份敌2整份敌3整份敌4整份...

←------------------ 连续一大块 ------------→

循环从头扫到尾时,CPU 按块预取,一次缓存行能服务好几个元素。

对比:对象数组(Enemy是class)

Enemy\[\](元素是引用)往往是:

数组里: 指针1指针2指针3... ← 指针本身连续

堆上: 敌1在东,敌2在西,敌3在南 ← 对象本体分散

循环时要"跳来跳去"找对象,缓存经常对不上,就慢。

所以结构体数组的cpucache命中率高

CPU Cache(L1/L2/L3)

最常见瓶颈

连续访问 → 命中率高,这是主因

Burst 适合"算得多、逻辑单纯、重复次数极高"的场景,不适合 UI、网络、杂乱玩法逻辑。

相关推荐
HH‘HH6 小时前
Unity 相机与光照调整:从基础到进阶的实战指南
unity
HH‘HH1 天前
Unity引擎界面各个功能面板详细介绍
unity·游戏引擎
℡枫叶℡1 天前
Unity 2D资产命名常用缩写
unity·资产命名缩写
丁小未1 天前
Unity AssetBundle商业化项目资源方案
unity·游戏引擎·assetbundle·unity框架
unityのkiven1 天前
通过 Unity 实现杀戮尖塔2式卡牌系统与机制
unity·游戏引擎
郝学胜-神的一滴1 天前
中级OpenGL教程 020:巧用数组与循环实现多点点光源渲染,告别冗余代码重构方案
c++·unity·游戏引擎·godot·图形渲染·unreal
Duo1J1 天前
【UE】Slate 编辑器工具开发01 - Slate语法 & 常用控件
ue5·编辑器·游戏引擎·ue4
qq_170264751 天前
unity的锁帧和垂直同步
unity·游戏引擎
承渊政道1 天前
飞算Java炫技赛:Java×Unity数字孪生园区平台的从零落地记录
java·开发语言·unity·技术分享·vibe coding·飞算javaai·飞算java ai炫技赛