Search Unity

ComponentSystem vs JobComponentSystem

Discussion in 'Entity Component System' started by xenonsin, Apr 11, 2018.

  1. xenonsin

    xenonsin

    Joined:
    Dec 12, 2013
    Posts:
    20
    I'm bit confused on when to use one over the other. What are some use cases where I would use ComponentSystem but not JobComponentSystem and vice versa? Wouldn't it be more performant to execute most systems as jobs?

    For example, in the PURE ECS sample why are the RemoveDeadSystem, ShotDamageSystem, EnemyShootSystem, and EnemyRemovalSystem... JobComponentSystems while the others are ordinary ComponentSystems?
     
    Last edited: Apr 11, 2018
  2. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    JobComponentSystem is the preferred way for stuff that CAN be jobified. not everything (currently) can.

    currently you have to be on the main thread to call existing Unity APIs or use reference types, and that will remain.

    eventually there will be a jobified API for everything.
     
  3. xenonsin

    xenonsin

    Joined:
    Dec 12, 2013
    Posts:
    20
    I see! So eventually JobComponentSystems will be the new standard and everything would essentially be multithreaded.

    What do you mean by "use reference types"? sorry I'm a bit new
     
  4. recursive

    recursive

    Joined:
    Jul 12, 2012
    Posts:
    669
    In .NET there are 2 fundamental object types, Value types and Reference types.

    All structs are value types (along with the fundamental numeric types and stuff like enums) and are handled directly on the stack or stored directly in memory as part of another object. Value types don't need to be garbage collected, as they aren't allocated on the heap themselves (they may be part of an object that IS allocated on the heap, or contain a reference to an object on the heap, see below).

    All classes (and strings) are reference types (including ALL Unity.Object-derived classes, such as MonoBehaviour and ScriptableObject, etc). They are instantiated on the heap and handled by reference pointers. They are also candidates for garbage collection, and can contain value types (directly in their allocated memory block) or references to other reference type instances.
     
    Nyanpas, leni8ec, rudypoo and 4 others like this.
  5. xenonsin

    xenonsin

    Joined:
    Dec 12, 2013
    Posts:
    20
    Thank you recursive and M_R :)
     
  6. Floofloof

    Floofloof

    Joined:
    Nov 21, 2016
    Posts:
    41
    Asking for clarification:
    So ComponentSystems are on the main thread and can be thought of as say a monobehaviour update (i.e. called once a frame and allow access to UnityEngine dlls). You would [Inject] ComponentData arrays that you would iterate over if needed.

    A JobComponentSystem is almost the same thing except it jobifies the end result of the (main thread) Update for multithreading?
     
  7. recursive

    recursive

    Joined:
    Jul 12, 2012
    Posts:
    669
    Correct. Both have the same injection capabilities.

    The JobComponent System simply takes in a JobHandle representing it's dependencies and produces a JobHandle representing all of it's jobs (there are functions to combine JobHandles scheduling them). If there's no work to be done (early out) a JobComponentSystem can simply return the dependency JobHandle it was given instead of scheduling anything.

    A Barrier System (such as EndFrameBarrier and TransformInputBarrier) doesn't do any real processing of it's own, but acts as a sync point for executing EntityCommandBuffers, which are a way of batching entity changes (create/destroy entity, add/set/remove component) instead of executing them immediately (which can be slower or have issues with one thread destroying an entity or component while another thread is still trying to use it).
     
  8. Floofloof

    Floofloof

    Joined:
    Nov 21, 2016
    Posts:
    41
    Thanks that really clears things up for me. I dont come from a ECS background so some of the naming conventions and rules between ECS and the Job system kinda confused me. The way I interpenetrated Unity it seemed as if they were one in the same or extremely similar so I wasnt exactly sure which rules applied where or why. I think this really clears things up for me.
     
    recursive likes this.
  9. wang37921

    wang37921

    Joined:
    Aug 1, 2014
    Posts:
    102
    JobComponentSystem's OnUpdate is also execute on main thread? can use classic Unity API?
    @recursive
     
  10. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    All systems executes on main thread, CS and JCS both, difference only in automatic dependencies. Only Jobs can run in different thread (but scheduled only on main thread)
     
    leni8ec and wang37921 like this.
  11. wang37921

    wang37921

    Joined:
    Aug 1, 2014
    Posts:
    102
    thx
     
  12. kork

    kork

    Joined:
    Jul 14, 2009
    Posts:
    280
    I wouldn't go that far. Not everything can or should be jobified. Sometimes it's just simpler (and maybe even faster) to do a small thing on the main thread instead of spawning a job for this and having to manage the complexity and cognitive overhead of stuff happening in multiple threads.
    ComponentSystem
    will probably stay relevant even when most of Unity API is integrated with ECS as you cannot parallelize everything - some things intrinsically need to happen one thing at a time.
     
    leni8ec, learc83 and zephyr831125 like this.
  13. wang37921

    wang37921

    Joined:
    Aug 1, 2014
    Posts:
    102
    JCS automatic dependencies.
    if schedule a job, in JCS's OnUpdate, and return its handle:
    Code (CSharp):
    1. protected override JobHandle OnUpdate(JobHandle inputDeps)
    2. {
    3.     return job.Schedule(inputDeps);
    4. }
    In the JCS's next OnUpdate, has the job (last scheduled in this JCS) completed?
     
  14. kork

    kork

    Joined:
    Jul 14, 2009
    Posts:
    280
    Yes, because there is code in the
    JobComponentSystem
    base class which keeps track of the jobs that were scheduled last frame and will wait for them to finish before running the
    OnUpdate
    method again. This is to avoid "infinite dependency chains", at least so it reads in the code.
     
    leni8ec likes this.
  15. wang37921

    wang37921

    Joined:
    Aug 1, 2014
    Posts:
    102
    thx
     
  16. radiantboy

    radiantboy

    Joined:
    Nov 21, 2012
    Posts:
    1,633
    I cant get JobComponentSystem to import, any ideas?
     
  17. CaseyHofland

    CaseyHofland

    Joined:
    Mar 18, 2016
    Posts:
    613
    The JobComponentSystem can do that too. We'll probably still be able to inherit from the ComponentSystem for a long time since I don't see it going before ECS 1.0.0 and once it's part of the API deprecating it will take a long time, but essentially: yes, you can do the same thing with JobComponentSystem as with ComponentSystem but more. The added cost is negligible so I say shoot for ease of use: always use JobComponentSystem.
     
    Last edited: Jul 12, 2020
  18. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Both deprecated. The only right way which you should use for everything - SystemBase.
     
    charleshendry and CaseyHofland like this.
  19. CaseyHofland

    CaseyHofland

    Joined:
    Mar 18, 2016
    Posts:
    613
    The SystemBase OnUpdate does not give you an inputDependency however. Are you sure they are deprecated?
     
  20. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Yes, they deprecated. SystemBase has Dependency property. Moreover Entities.ForEach\Job.WithCode handles this automatically as ILPP will compile it to IJobChunk and will handle Dependency for you.
     
    CaseyHofland likes this.
  21. KAV2008

    KAV2008

    Joined:
    Aug 13, 2020
    Posts:
    11
    So does it mean the most preferable replacement for ComponentSystem.PostUpdateCommands() for now is to use EntityCommandBuffer in SystemBase?
     
  22. desertGhost_

    desertGhost_

    Joined:
    Apr 12, 2018
    Posts:
    260
    Yes. If you need the changes to be applied directly after your job runs, then you should create an EntityCommandBuffer in the system's update method and play it back with the systems entity manager. This will create an additional sync point. If you don't want the additional sync point and you can delay the playback, then you should get the EntityCommandBuffer from one of the existing system (e.g. EndSimulationEntityCommandBufferSystem).
     
    DotusX likes this.
  23. KAV2008

    KAV2008

    Joined:
    Aug 13, 2020
    Posts:
    11
    Thank you, that's quite helpful;)