05 — Job System¶
Parallel entity processing with Unity's job system and Burst compiler. Shows both main-thread and job-based approaches side by side.
Source: Samples/05_JobSystem/
What It Does¶
Particles spawn, move, and bounce off boundaries. A toggle switches between main-thread and Burst-compiled parallel job execution, so we can see performance changes (using burst+jobs is often 10x faster). Arrow keys adjust particle count.
Schema¶
Components¶
Position, Velocity, Rotation, UniformScale, ColorComponent, GameObjectId from Common, plus global components for configuration:
public struct DesiredNumParticles : IEntityComponent { public int Value; }
public struct IsJobsEnabled : IEntityComponent { public bool Value; }
Templates¶
public partial class ParticleEntity : ITemplate,
IExtends<CommonTemplates.Renderable>,
IHasTags<SampleTags.Particle>
{
public Velocity Velocity;
}
public partial class Globals : ITemplate, IExtends<TrecsTemplates.Globals>
{
public DesiredNumParticles DesiredNumParticles;
public IsJobsEnabled IsJobsEnabled;
}
Systems¶
ParticleMoveSystem — Job vs Main Thread¶
The system defines both a main-thread and a [WrapAsJob] version of the same logic, and switches between them at runtime:
public partial class ParticleMoveSystem : ISystem
{
[ForEachEntity(Tag = typeof(SampleTags.Particle))]
void ExecuteMainThread(in Velocity velocity, ref Position position)
{
position.Value += World.DeltaTime * velocity.Value;
}
[ForEachEntity(Tag = typeof(SampleTags.Particle))]
[WrapAsJob]
static void ExecuteAsJob(
in Velocity velocity,
ref Position position,
in NativeWorldAccessor world
)
{
position.Value += world.DeltaTime * velocity.Value;
}
public void Execute()
{
if (World.GlobalComponent<IsJobsEnabled>().Read.Value)
{
ExecuteAsJob();
}
else
{
ExecuteMainThread();
}
}
}
Note how the job version is static and uses NativeWorldAccessor instead of World, while the main-thread version is an instance method that accesses World directly.
Behind the scenes, the source generator creates a simple job struct that calls the static method for each entity, and a wrapper method that resolves groups, wires up dependencies, and schedules the job:
// Generated by source generator (simplified)
// Generated wrapper — this is what you call from Execute()
void ExecuteAsJob()
{
var job = new ExecuteAsJob_AutoJob();
// ...
// For each matching group: populate buffers, wire up dependencies, schedule
job.ScheduleParallel(count, batchSize, dependencies);
// ... track job for dependency system ...
}
[BurstCompile]
struct ExecuteAsJob_AutoJob : IJobFor
{
public NativeComponentBufferRead<Velocity> Velocities;
public NativeComponentBufferWrite<Position> Positions;
public NativeWorldAccessor World;
public void Execute(int i)
{
// Calls your static method for each entity
ParticleMoveSystem.ExecuteAsJob(
in Velocities[i], ref Positions[i], in World);
}
}
The generated ExecuteAsJob() method resolves groups, wires up dependency tracking, and schedules the job — so you just call it and the rest is handled.
ParticleSpawnerSystem — Job-Based Entity Creation¶
When spawning entities inside jobs, entity handles must be reserved on the main thread beforehand. This is because multiple job threads may create entities in parallel, and without pre-reserved handles, the assigned IDs would depend on thread scheduling order. Reserving handles upfront guarantees deterministic IDs, which is important because the handles can be used immediately inside the job (e.g., to set up cross-entity references).
// Reserve handles on main thread
var handles = World.ReserveEntityHandles(count, Allocator.TempJob);
// Schedule spawn job
new SpawnJob
{
ReservedHandles = handles,
// ...
}.Schedule(count, 64);
Inside the job:
nativeWorld.AddEntity<SampleTags.Particle>(
sortKey: (uint)index,
reservedRef: reservedHandles[index])
.Set(new Position(pos))
.Set(new Velocity(vel));
Concepts Introduced¶
[WrapAsJob]— source generator creates the parallel burst compiled iterationNativeWorldAccessorfor structural operations in jobsReserveEntityHandlesfor pre-allocating stable handles before parallel creation- Sort keys for deterministic ordering of job-created entities