BurstCompile で Unity の計算を速くする
C# の一部を LLVM でネイティブコードにコンパイルして高速化する Burst 入門。Job System との組み合わせ・書ける C# の制約・SIMD まで。
大量の座標計算やシミュレーションを回すと、通常の C# では速度が足りなくなることがあります。Burst は、C# の一部を LLVM で最適化ネイティブコードに変換して、そうした計算を桁違いに速くするコンパイラです。この記事では、Burst の仕組み・Job System との組み合わせ・書ける C# の制約・SIMD までを押さえます。
Burst とは何か
Burst は Unity 製のコンパイラで、[BurstCompile] を付けたコードを HPC#(High Performance C#) という C# のサブセットとして解釈し、LLVM でネイティブコードにコンパイルします。狙いは、SIMD ベクトル化・GC 非依存・積極的な最適化仮定による数値計算の高速化です。
⭐ Burst はすべての C# を速くする魔法ではない。効くのは Job System 上で回す「managed オブジェクトを触らない数値ループ」。UI やゲームロジック全体が速くなるわけではない。
🧭 純粋な C# も JIT(RyuJIT)で最適化されるが、Burst は「参照が絡まない・GC しない」と割り切ったサブセットに限定することで、さらに踏み込んだ SIMD 最適化をかける。
使い方(Job System と組む)
Burst は基本的に C# Job System とセットで使います。IJob 系を実装した struct に [BurstCompile] を付けます。
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
[BurstCompile]
struct MultiplyJob : IJobParallelFor
{
[ReadOnly] public NativeArray<float> Input;
public NativeArray<float> Output;
public void Execute(int i) => Output[i] = Input[i] * 2f;
}
// 呼び出し側(メインスレッド、ここは通常の managed C#)
var handle = new MultiplyJob { Input = input, Output = output }
.Schedule(input.Length, 64);
handle.Complete(); // 完了を待って結果を使う
⚠️
Scheduleしただけでは終わっていない。結果を使う前にComplete()(または依存関係で待つ)を忘れると、未完了データを読む・破棄済みバッファを触るなどで落ちる。
書ける C# の制約(HPC#)
Burst ジョブの中では managed(参照型)を一切使えません。ここが最大の壁です。
| 使えないもの | 代わりに |
|---|---|
class / 参照型のフィールド | struct・blittable な値型のみ |
new によるヒープ確保・GC | NativeArray など Unity.Collections |
string・ボクシング・LINQ | 使わない(数値と配列で組む) |
例外の多用・try/catch | 事前チェックで避ける |
可変な static フィールド | readonly か SharedStatic<T> |
🧭 通常の C# なら当たり前の
new List<T>()や LINQ が、Burst ジョブ内では使えない。「配列とプリミティブだけで計算する」つもりで書く。
Unity.Mathematics と SIMD
Burst の性能を引き出すには、Unity.Mathematics(float3 / math.*)を使います。これらは SIMD にマップされ、ベクトル演算が一括で処理されます。
using Unity.Mathematics;
[BurstCompile]
struct MoveJob : IJobParallelFor
{
public NativeArray<float3> Positions;
public float3 Velocity;
public float Dt;
public void Execute(int i) => Positions[i] += Velocity * Dt; // ベクトル演算がSIMD化
}
💡
System.MathではなくUnity.Mathematics.math(math.sqrt,math.dotなど)を使う。Burst はこれらを認識して最適化する。
生成された機械語は Burst Inspector(Jobs > Burst > Open Inspector)で確認でき、SIMD 命令が出ているか、最適化が効いているかを見られます。
まとめ
- Burst は
[BurstCompile]を付けたコードを LLVM でネイティブ化し、数値計算を高速化するコンパイラ。万能ではなく、対象は Job System 上の数値ループ。 - 使い方は C# Job System とセット。
IJob系 struct に[BurstCompile]を付け、Schedule→Completeで回す。 - ジョブ内では managed(
class・new・string・LINQ)が使えない。structとNativeArrayで組む。 Unity.Mathematics(float3/math.*)を使うと SIMD が効く。結果は Burst Inspector で確認できる。
次にやること: IJobParallelFor の Schedule バッチサイズ調整や、ジョブ間の依存関係(JobHandle の連結)、さらに DOTS/ECS と組み合わせた大規模処理へ進むと、Burst の真価が出る。