Job System – Part 2

This is the second part of my series of articles about Job System, you can read my first article here:

https://mauroubaldo.com/job-system-part-1/

Now let’s talk about Native Containers with Jobs.

For Start this article I would like a quote from Unity’s official documentation, about what is Native Containers.

“A Native Container is a managed value type that provides a safe C# wrapper for native memory. It contains a pointer to an unmanaged allocation. When used with the Unity C# Job System, a Native Container allows a job to access data shared with the main thread rather than working with a copy.” Unity Documentation.

For more Infos, you can see the official documentation here: https://docs.unity3d.com/Manual/JobSystemNativeContainer.html

Now that we know what are Native Containers, we can talk about the types of native containers.

What are the types?

According to Unity documentation, the types are:

NativeArray – This is responsible for exposing a buffer of native memory for managed code.

NativeList – This is a resizable native array.

NativeHashMap – These are keys and value pairs.

NativeMultiHashMap – These are multiple values per key.

NativeQueue – This is a queue.

For more Infos you can see the official documentation mentioned in this part of this article:

NativeArray: https://docs.unity3d.com/ScriptReference/Unity.Collections.NativeArray_1.html

NativeCollections: https://docs.unity3d.com/Manual/JobSystemNativeContainer.html

For this article, I will only show the native array, because the native array does not need a preview package, but if you want to see other collections, you can search for Entity Component System (ECS) package.

How does it work?

Firstly you need to import the namespace Unity.Collections, at the moment that I am writing this article the Unity Engine only has available the NativeArray but in Entity Component System (ECS) package as mentioned, exist other Collections.

For this Article, I will use NativeArray.

Creating a NativeArray

For to create a NativeArray you only need to make this:

NativeArray<int> myNativeArray;

How to initialize a Native Array?

You can initialize a native array thus:

myNativeArray = new NativeArray<int>(arrayLenght, Allocator.Persistent);

Or using some constructor, NativeArray has three constructors, they are:

        public NativeArray(T[] array, Allocator allocator);
        public NativeArray(NativeArray<T> array, Allocator allocator);
        public NativeArray(int length, Allocator allocator, NativeArrayOptions options = NativeArrayOptions.ClearMemory);

Repair that We need to define an allocator, and Now I will explain what is this.

An Allocator is an Enumerator used to specify the type of allocation for our Native Array.

Using a native collection we need to use a memory allocator type.

An allocator can have three types:

Persistent: this is a very slow allocation, but your data may be available all the necessary time.

Temp: is a very fast allocation, but your lifetime is 1 frame or minus.

TempJob: is more fast than persistent but more slowly than temp, and your lifetime is 4 frames or minus.

For more info, you can check the official documentation here: https://docs.unity3d.com/Manual/JobSystemNativeContainer.html

In this article, I only will use a Persistent allocator, because is a very simple example, but I suggest that you test other allocators, as an exercise for improving your knowledge.

Now, that We know how to create a native array, let’s talk about how to work with a NativeArray.

The way to work with native arrays is the same as in other fields, but with a particularity, with the native array, you can copy values and paste them into other variables, after the end of the Job.

For example:

using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using Unity.Jobs;

public class JobExample2 : MonoBehaviour
{

    NativeArray<int> myFirstNativeArray;
    NativeArray<int> mySecondNativeArray;
    NativeArray<int> myResultNativeArray;
    int[] myFirstArray;
    int[] mySecondArray;
    public int[] myResultArray;

    MyJobWithArray myJobWithArray;
    JobHandle myJobWithArrayHandle;

    struct MyJobWithArray : IJob
    {

        public NativeArray<int> myJobNativeArray;
        public NativeArray<int> myJobNativeArray2;
        public NativeArray<int> myJobResultNativeArray;

        public void Execute()
        {
            for (int i = 0; i < myJobNativeArray.Length; i++)
                myJobResultNativeArray[i] = myJobNativeArray[i] + myJobNativeArray2[i];
        }
    }

    void Awake()
    {

        myFirstArray = new int[] { 1, 2, 3, 4};
        mySecondArray = new int[] { 5, 6, 7, 8 };
        myResultArray = new int[4];

        myFirstNativeArray = new NativeArray<int>(myFirstArray, Allocator.Persistent);
        mySecondNativeArray = new NativeArray<int>(mySecondArray, Allocator.Persistent);
        myResultNativeArray = new NativeArray<int>(myResultArray, Allocator.Persistent);

        myJobWithArray = new MyJobWithArray
        {
            myJobNativeArray = myFirstNativeArray,
            myJobNativeArray2 = mySecondNativeArray,
            myJobResultNativeArray = myResultNativeArray
        };

        myJobWithArrayHandle = myJobWithArray.Schedule();
    }


    void Start()
    {
        myJobWithArrayHandle.Complete();
        myJobWithArray.myJobResultNativeArray.CopyTo(myResultArray);

        for (int i = 0; i < myResultArray.Length; i++)
            Debug.LogError(myResultArray[i]);

        myFirstNativeArray.Dispose();
        mySecondNativeArray.Dispose();
        myResultNativeArray.Dispose();
    }

}

So here you can see how to copy the data of a Job for your code without value loss.

For the last is important to see that, I am using the method Dispose, this is to deallocate the memory allocated for use of the array.

Follow me on Instagram to stay known when I create new posts.

You can also leave your feedback, and suggestion, I will read them all, and I will answer for you.

Thanks for reading.