Search Unity

Looking for example how to do a long running job

Discussion in 'Entity Component System' started by mentics, Jan 19, 2020.

  1. mentics

    mentics

    Joined:
    Aug 18, 2015
    Posts:
    10
    I found this:
    https://forum.unity.com/threads/bes...usly-running-job-systems.720530/#post-4813451
    and think I was somewhat able to follow it, but I get various errors trying to make it work such as:
    InvalidOperationException: The previously scheduled job TestAsync2System:<>c__DisplayClass_schedule_LambdaJob0 reads from the NativeArray <>c__DisplayClass_schedule_LambdaJob0.safety. You must call JobHandle.Complete() on the job TestAsync2System:<>c__DisplayClass_schedule_LambdaJob0, before you can deallocate the NativeArray safely.

    and warnings like:
    Internal: JobTempAlloc has allocations that are more than 4 frames old - this is not allowed and likely a leak


    Am I doing something wrong? I tried it without the logs and timing and saw same errors, so those aren't causing it. It does seem to be running as expected, but all the warnings and errors are concerning.

    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Jobs;
    3.  
    4. public class TestAsync2System : JobComponentSystem {
    5.     int count = 0;
    6.     JobHandle jobHandle;
    7.  
    8.     protected override void OnCreate() {
    9.         RequireSingletonForUpdate<AsyncTag>();
    10.     }
    11.  
    12.     protected override JobHandle OnUpdate(JobHandle inputDependencies) {
    13.         UnityEngine.Debug.Log("OnUpdate");
    14.         if (count == 0) {
    15.             schedule(inputDependencies);
    16.             UnityEngine.Debug.Log("inc count: "+count);
    17.             count++;
    18.         } else {
    19.             if (jobHandle.IsCompleted) {
    20.                 UnityEngine.Debug.Log("completed: "+count);
    21.                 jobHandle.Complete();
    22.                 count = 0;
    23.             }
    24.         }
    25.         return inputDependencies;
    26.     }
    27.  
    28.     private void schedule(JobHandle inputDependencies) {
    29.         jobHandle = Entities.WithAll<AsyncTag>().WithoutBurst().ForEach((Entity e) => {
    30.             System.Diagnostics.Stopwatch s = System.Diagnostics.Stopwatch.StartNew();
    31.             UnityEngine.Debug.Log("starting: " + s.ElapsedMilliseconds);
    32.             System.Threading.Thread.Sleep(1000);
    33.             UnityEngine.Debug.Log("finished: " + s.ElapsedMilliseconds);
    34.         }).Schedule(inputDependencies);
    35.     }
    36. }
     
  2. mentics

    mentics

    Joined:
    Aug 18, 2015
    Posts:
    10
    I think I have this figured out. The JobTempAlloc warnings were either caused by some other system I had in the project, or when you use a NativeArray for a long running job, you cannot use the TempJob allocator, but Persistent works.

    And the error is probably that Entities.ForEach isn't made for this use case because it takes care of things for you that you don't want. Changing the "schedule" method in the above example to this works:

    Code (CSharp):
    1.     private void schedule(JobHandle inputDependencies) {
    2.             jobHandle = Job.WithoutBurst().WithCode(() => {
    3.                     System.Threading.Thread.Sleep(1000);
    4.         }).Schedule(inputDependencies);
    5.     }
    6.  
    The "WithoutBurst is only required because of the thread.sleep. Changing it to a spin wait works with burst except you get an error:
    (0,0): Burst error BC1049: Zero-size empty struct `TestAsync2System/<>c__DisplayClass_schedule_LambdaJob0` is not supported. To fix this issue, apply this attribute to the struct: `[StructLayout(LayoutKind.Sequential, Size = 1)]`.


    unless you create a NativeArray in it:

    Code (CSharp):
    1.     private void schedule(JobHandle inputDependencies) {
    2.         NativeArray<bool> result = new NativeArray<bool>(1, Allocator.Persistent);
    3.         result[0] = false;
    4.                 jobHandle = Job.WithDeallocateOnJobCompletion(result).WithCode(() => {
    5.                     for (long i = 0; i < 100000000; i++) {
    6.                 }
    7.             result[0] = true;
    8.         }).Schedule(inputDependencies);
    9.     }
    10.