Search Unity

Better way to use static methods in jobs (lots of parameters) ?

Discussion in 'Entity Component System' started by meanmonkey, Aug 28, 2019.

  1. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    Because of the burst restrictions I can't use object references or instanced methods in jobs, which is fine.

    I don't want to rewrite / duplicate methods for each job, so I'll have to stick with static methods, which are allowed in jobs.

    This works fine but the downside is I have to pass quite large parameters lists (lots of native arrays, and always the same) to these static methods over and over again, which is painful to maintain.

    Any ideas for a better approach here ? ... Thanks
     
  2. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    529
    Put the parameters into a struct?
     
    meanmonkey likes this.
  3. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    This is a nice idea, but then I would have to pass the parameters to the struct again in each job before calling the method, so the problem is only diverted.

    Anyway it would be helpful if was was allowed to pass a struct holding all nativearrays to a job instead of passing every single nativearray. Then I would create kinda centralized data struct holding all my default nativearrays and pass it as a single struct to the job, and forward it to the static method.

    You think that's feasable ?
     
  4. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,759
    Put your logic in a separate struct.
    Some example code from a project of mine.

    Implementation

    Code (CSharp):
    1. public struct ClearVisionImpl
    2.     {
    3.         /// <summary>
    4.         /// Team to Entity map.
    5.         /// </summary>
    6.         [ReadOnly]
    7.         public NativeArray<Entity> TeamToEntity;
    8.  
    9.         /// <summary>
    10.         /// The VersionHistory buffers.
    11.         /// </summary>
    12.         [NativeDisableParallelForRestriction]
    13.         public BufferFromEntity<VisionElement> VisionElement;
    14.  
    15.         /// <summary>
    16.         /// The VersionHistory buffers.
    17.         /// </summary>
    18.         [ReadOnly]
    19.         public BufferFromEntity<VisionHistoryElement> VisionHistory;
    20.  
    21.         // ...
    22.  
    Job1

    Code (CSharp):
    1.     [ExcludeComponent(typeof(Observer))]
    2.     [BurstCompile]
    3.     public struct ClearVisionObserverRemovedJob : IJobForEachWithEntity_EBC<ObserverHistoryElement, ObserverHistory>
    4.     {
    5.         /// <summary>
    6.         /// The clear vision implementation.
    7.         /// </summary>
    8.         public ClearVisionImpl Impl;
    9.  
    10.         /// <inheritdoc />
    11.         public void Execute(Entity entity, int index, DynamicBuffer<ObserverHistoryElement> historyElements, [ReadOnly] ref ObserverHistory history)
    12.         {
    13.             this.Impl.Execute(history.Team, historyElements);
    14.         }
    15.     }
    Job2

    Code (CSharp):
    1.     [BurstCompile]
    2.     public struct ClearVisionObserverChangedJob : IJobNativeMultiHashMapVisitKeyValue<int, Entity>
    3.     {
    4.         /// <summary>
    5.         /// Get the observer history buffer from entity.
    6.         /// Only used once per entity so NativeDisableParallelForRestriction is safe.
    7.         /// </summary>
    8.         [NativeDisableParallelForRestriction]
    9.         public BufferFromEntity<ObserverHistoryElement> ObserverHistoryElements;
    10.  
    11.         /// <summary>
    12.         /// The clear vision implementation.
    13.         /// </summary>
    14.         public ClearVisionImpl Impl;
    15.  
    16.         /// <inheritdoc />
    17.         public void ExecuteNext(int team, Entity entity)
    18.         {
    19.             var observerHistory = this.ObserverHistoryElements[entity];
    20.             this.Impl.Execute(team, observerHistory);
    21.         }
    22.     }
     
    Antypodish and meanmonkey like this.
  5. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    This is exactly what I was looking for. Thank you so much!!!
     
  6. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    529
    You can.
     
    meanmonkey likes this.
  7. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    This works very good for me....one thing which comes up to my mind now is performance wise:

    The job system is (internally) creating a copy of each nativecollection, at least if it's not [ReadOnly], so I understand.

    So when I pass kinda default struct (holding many nativearrays) to serveral jobs now, will the job system create a copy of each nativearray each execute regardless if it is used in the job ? Or will the job only create copies of nativearrays which are operated on ?

    I want to add I'm not pushing ALL of my data into a single struct now. It still is clean and separated...but still I want to know.
     
    Last edited: Aug 29, 2019
  8. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    529
    No, they are never copied. All jobs operate on the same memory. Jobs with ReadOnly access to the same container may run at the same time while a job having write access needs to run separately. So passing unused arrays might require additional dependencies eg when a writable container is not used at all but the actual performance cost of passing the arrays to the job is negligible.
     
    meanmonkey likes this.
  9. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    Ok got it, thanks!