Documentation

Unity Engine


User Manual

Script Reference

Unity Engine


Parallel readers and writers

Use parallel readers and writers to safely read from and write to unmanaged collections in Unity.
Read time 2 minutesLast updated 6 days ago

Several of the collection types have nested types to read and write from parallel jobs. For example, to write safely to a
NativeList<T>
from a parallel job, you need to use
NativeList<T>.ParallelWriter
:
NativeList<int> nums = new NativeList<int>(1000, Allocator.TempJob); // The parallel writer shares the original list's AtomicSafetyHandle. var job = new MyParallelJob {NumsWriter = nums.AsParallelWriter()};
public struct MyParallelJob : IJobParallelFor { public NativeList<int>.ParallelWriter NumsWriter; public void Execute(int i) { // A NativeList<T>.ParallelWriter can append values // but not grow the capacity of the list. NumsWriter.AddNoResize(i); } }
Note that these parallel readers and writers don't support the full functionality of the collection. For example, a
NativeList
can't grow its capacity in a parallel job because there's no way to safely allow this without incurring a synchronization overhead.

Deterministic reading and writing

Although a
ParallelWriter
ensures the safety of concurrent writes, the order of the concurrent writes is non-deterministic because it depends on thread scheduling, which is controlled by the operating system and other factors outside your program's control. This means the final arrangement of written data can differ from run to run.
Concurrent reads don't have this problem in the same way. A parallel reader ensures the safety of concurrent reads. While the timing and order in which reads complete depends on thread scheduling, the value each read observes is determined by the index or key your job code supplies rather than by which thread executes that read. Thread scheduling changes which worker runs a given iteration, not which value that iteration reads.
To achieve a deterministic order of writes, you can use either
NativeStream
or
UnsafeStream
, which split writes into a separate buffer per thread. Alternatively, you can deterministically sort the data after it has been written.
If you need read results to be deterministic while data is being concurrently modified, that requires explicit synchronization or a design that separates the read and write phases.

Additional resources