Using Job.WithCode
The Job.WithCode construction provided by the SystemBase class is an easy way to run a function as a single background job. You can also run Job.WithCode on the main thread and still take advantage of Burst compilation to speed up execution.
The following example uses one Job.WithCode lambda function to fill a native array with random numbers and another job to add those numbers together:
public partial class RandomSumJob : SystemBase
{
private uint seed = 1;
protected override void OnUpdate()
{
Random randomGen = new Random(seed++);
NativeArray<float> randomNumbers
= new NativeArray<float>(500, Allocator.TempJob);
Job.WithCode(() =>
{
for (int i = 0; i < randomNumbers.Length; i++)
{
randomNumbers[i] = randomGen.NextFloat();
}
}).Schedule();
// To get data out of a job, you must use a NativeArray
// even if there is only one value
NativeArray<float> result
= new NativeArray<float>(1, Allocator.TempJob);
Job.WithCode(() =>
{
for (int i = 0; i < randomNumbers.Length; i++)
{
result[0] += randomNumbers[i];
}
}).Schedule();
// This completes the scheduled jobs to get the result immediately, but for
// better efficiency you should schedule jobs early in the frame with one
// system and get the results late in the frame with a different system.
this.CompleteDependency();
UnityEngine.Debug.Log("The sum of "
+ randomNumbers.Length + " numbers is " + result[0]);
randomNumbers.Dispose();
result.Dispose();
}
}
Note
To run a parallel job, implement IJobFor, which you can schedule using ScheduleParallel() in the system OnUpdate() function.
Variables
You cannot pass parameters to the Job.WithCode lambda function or return a value. Instead, you can capture local variables in your OnUpdate() function.
When you schedule your job to run in the C# Job System using Schedule()
, there are additional restrictions:
- Captured variables must be declared as NativeArray -- or other native container -- or a blittable type.
- To return data, you must write the return value to a captured native array, even if the data is a single value. (Note that you can write to any captured variable when executing with
Run()
.)
Job.WithCode provides a set of functions to apply read-only and safety attributes to your captured native container variables. For example, you can use WithReadOnly
to designate that you don't update the container and WithDisposeOnCompletion
to automatically dispose a container after the job finishes. (Entities.ForEach provides the same functions.)
See Job.WithCode for more information about these modifiers and attributes.
Executing the function
You have two options to execute your lambda function:
Schedule()
-- executes the function as a single, non-parallel job. Scheduling a job runs the code on a background thread and thus can take better advantage of available CPU resources.Run()
-- executes the function immediately on the main thread. In most cases the Job.WithCode can be Burst compiled so executing code can be faster inside Job.WithCode even though it is still run on the main thread.
Note that calling Run()
automatically completes all the dependencies of the Job.WithCode construction. If you do not explicitly pass a JobHandle object to Run()
the system assumes that the current Dependency property represents the function's dependencies. (Pass in a new JobHandle if the function has no dependencies.)
Dependencies
By default, a system manages its ECS-related dependencies using its Dependency property. The system adds each job created with Entities.ForEach and Job.WithCode to the Dependency job handle in the order that they appear in the OnUpdate() function. You can also manage job dependencies manually by passing a JobHandle to your Schedule
functions, which then return the resulting dependency. See Dependency for more information.
See Job dependencies for more general information about job dependencies.