Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Using static methods with Job System

Discussion in 'C# Job System' started by m1n1m1, Oct 11, 2018.

  1. m1n1m1

    m1n1m1

    Joined:
    Sep 18, 2018
    Posts:
    4
    So I read in the documentation the accessing static variables is really bad but I couldn't find out anything about static functions. Let's assume I have the following Job.

    Code (CSharp):
    1. public struct JobCalculateVoxels : IJobParallelFor {
    2.  
    3.     public NativeArray<Voxel.Type> voxels;
    4.     public Vector3Int worldPos;
    5.     public static int size = ChunkScript.CHUNKSIZE;
    6.     public static FastNoise fastNoise;
    7.     public int seed;
    8.  
    9.     public JobCalculateVoxels(NativeArray<Voxel.Type> voxels, Vector3Int worldPos, int seed)
    10.     {
    11.         this.voxels = voxels;
    12.         this.worldPos = worldPos;
    13.         this.seed = seed;
    14.         fastNoise = new FastNoise(seed);
    15.         fastNoise.SetNoiseType(FastNoise.NoiseType.Simplex);
    16.     }
    17.  
    18.     public void Execute(int index)
    19.     {
    20.        
    21.         voxels[index] = ChunkManager.NoiseDensity(VoxelTerrain.IndexToVector3(index) + worldPos, fastNoise);
    22.         //voxels[index] = NoiseDensity(VoxelTerrain.IndexToVector3(index) + worldPos, fastNoise);
    23.     }
    24.  
    25. /*
    26.     public static Voxel.Type NoiseDensity(Vector3 point, FastNoise fastNoise)
    27.     {
    28.  
    29.         // float d = generator.GetValue(point * 0.04f) * 8.0f;
    30.         float d = fastNoise.GetNoise(point.x * 0.04f, point.y * 0.04f, point.z * 0.04f) * 8.0f;
    31.         d += 30;
    32.         d = point.y - d;
    33.  
    34.         if (d <= 0)
    35.             return Voxel.Type.earth;
    36.         else
    37.             return Voxel.Type.air;
    38.     }
    39. */
    40. }
    As you can see in Execute for every index I access the static function NoiseDensity on the class ChunkManager(It has the same logic as the fuction in this job). Is this good practice and safe code?

    I could also use the function in this job. Also accessing the function from outside does work so far but I'm still confused from the documentation.
     
  2. recursive

    recursive

    Joined:
    Jul 12, 2012
    Posts:
    669
    You should avoid accessing static variables or static functions that access static variables. They present performance/potential bug issues in non-burst jobs and I think are straight-up incompatible with Burst.

    Static methods that are purely functional (no static field access/side effects) or use constants defined elsewhere are fine. Functional static methods that call functional static methods are also fine.

    Functions on non-immutable structs that have side effects limited to that struct (no static field access) are also fine, but should be avoided unless it's the best/fastest option. In that vein, Job structs are ok to have local methods that access local fields, even in Burst (some of the Transform jobs do this, at least the earlier ones did).

    Is
    FastNoise
    a value-type or reference-type? If it's a reference type it's not safe to use in a Job. If it's a struct you can just add it as a normal field to the Job struct and access
    NoiseDensity()
    as a local method, unless it's used elsewhere.

    Edit:
    Also, if
    ChunkScript.CHUNKSIZE
    is a constant and in the enclosing type (I assume your job is nested in some system or monobehaviour class definition), you can just use it directly. If it's not, you can make it public and still access it directly, true constants shouldn't present a problem.
     
    GeorgeAdamon and m1n1m1 like this.
  3. m1n1m1

    m1n1m1

    Joined:
    Sep 18, 2018
    Posts:
    4
    Hello recursive, thank you very much for your answer.

    fastNoise is a object(so reference type) but isn't it okay, because I create a new Intance of it in the constructor, that only lives in the Job? So there is no way to write or read from it from another thread. Accessing as a local method also worked(without fastNoise parameter, and instead direct access) but I would like to use it from outside.

    About CHUNKSIZE you are propably right about using it directly. My idea generally was about caching the value because it is used often and gaining performance. CHUNKSIZE before was static so it made sense. RIght now though it's stupid because the Compiler just replaces CHUNKSIZE with the assigned value at compile time right?
     
  4. recursive

    recursive

    Joined:
    Jul 12, 2012
    Posts:
    669
    1. No. Since it's a reference type AND you're accessing it in the job, there's a possibility it could be moved by the GC while the job is executing. The unity job system doesn't run in the same threading context as .NET threads/Tasks, its run by the native C++ engine job system to eliminate the overhead of .NET threads. In the future they plan to use the Rosyln compiler tech to statically analyze for it and treat reference access in a job as a compiler error.

    If you can convert FastNoise to an unmanaged struct, it should be perfectly safe.

    Unity.Mathematics package also has some noise functions in the newer releases. That might help with a conversion.

    2. A static int isnt a compile time constant by design. Its allowed to set a static or static readonly value as early as the static constructor (first time an instance or static method of a class is accessed during runtime, it runs beforehand). Only const fields are initialized and evaluated at compile time. You can set a const field to another const field of the same type.
     
    m1n1m1 likes this.
  5. m1n1m1

    m1n1m1

    Joined:
    Sep 18, 2018
    Posts:
    4
    Thanks so much for the tip. I tried searching for a different c# noise library, but all use generators and therefore you have to allocate memory.

    However the new Unity.Mathematics does have 3D NoiseFunctions unlike the old package. And they are statically accessible aswell. So they work perfectly with jobs. Now I can Burst Compile my job too!

    Here is my updated code.

    Code (CSharp):
    1. using UnityEngine;
    2. using Unity.Jobs;
    3. using Unity.Collections;
    4. using Unity.Burst;
    5. using Unity.Mathematics;
    6.  
    7. [BurstCompile]
    8. public struct JobCalculateVoxels : IJobParallelFor {
    9.  
    10.     [WriteOnly]
    11.     public NativeArray<Voxel.Type> voxels;
    12.     public Vector3Int worldPos;
    13.     public int seed;
    14.  
    15.     public JobCalculateVoxels(NativeArray<Voxel.Type> voxels, Vector3Int worldPos, int seed)
    16.     {
    17.         this.voxels = voxels;
    18.         this.worldPos = worldPos;
    19.         this.seed = seed;
    20.     }
    21.  
    22.     public void Execute(int index)
    23.     {
    24.         voxels[index] = NoiseDensity(VoxelTerrain.IndexToVector3(index) + worldPos, seed);
    25.     }
    26.  
    27.     public static Voxel.Type NoiseDensity(Vector3 point, int seed)
    28.     {
    29.         float d = noise.snoise(new float3(point.x + seed, point.y + seed, point.z+ seed));
    30.         d += 30;
    31.         d = point.y - d;
    32.  
    33.         if (d <= 0)
    34.             return Voxel.Type.earth;
    35.         else
    36.             return Voxel.Type.air;
    37.     }
    38. }
     
    recursive likes this.