Search Unity

ETA on C# job system and new ECS?

Discussion in 'Entity Component System' started by David-T, Jan 10, 2018.

  1. David-T

    David-T

    Joined:
    Oct 6, 2012
    Posts:
    11
    From the blog post on this beta version, it sounds like the C# job system and new entity component system isn't available currently, but will be released during this beta cycle.

    When can we expect that and where should we look for news on its release?

    The Austin Unite 2017 video on ECS mentioned it would be made available first on Github. I'm mainly interested in getting familiar with the new ECS.
     
    Enrico-Monese and DirkMueller like this.
  2. Dennin-Dalke

    Dennin-Dalke

    Joined:
    Aug 10, 2014
    Posts:
    25
    I could find some classes from C# Job System in:
    • UnityEngine.Jobs
    • UnityEngine.Jobs.LowLevel.Unsafe

    But I haven't found anything related to the Entity Component System, probably it'll be added as dependency module.
     
  3. Deleted User

    Deleted User

    Guest

    Looks like Jobs are there (below code works fine):

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using Unity.Collections;
    4. using Unity.Jobs;
    5.  
    6. class ApplyVelocitySample : MonoBehaviour
    7. {
    8.     struct VelocityJob : IJob
    9.     {
    10.         // Jobs declare all data that will be accessed in the job
    11.         // By declaring it as read only, multiple jobs are allowed to access the data in parallel
    12.         [ReadOnly]
    13.         public NativeArray<Vector3> velocity;
    14.  
    15.         // By default containers are assumed to be read & write
    16.         public NativeArray<Vector3> position;
    17.  
    18.         // Delta time must be copied to the job since jobs generally don't have concept of a frame.
    19.         // The main thread waits for the job on the same frame or the next frame, but the job should
    20.         // perform work in a deterministic and independent way when running on worker threads.
    21.         public float deltaTime;
    22.  
    23.         // The code actually running on the job
    24.         public void Execute()
    25.         {
    26.             // Move the positions based on delta time and velocity
    27.             for (var i = 0; i < position.Length; i++)
    28.                 position[i] = position[i] + velocity[i] * deltaTime;
    29.         }
    30.     }
    31.  
    32.     public void Update()
    33.     {
    34.         var position = new NativeArray<Vector3>(500, Allocator.Persistent);
    35.  
    36.         var velocity = new NativeArray<Vector3>(500, Allocator.Persistent);
    37.         for (var i = 0; i < velocity.Length; i++)
    38.             velocity[i] = new Vector3(0, 10, 0);
    39.  
    40.  
    41.         // Initialize the job data
    42.         var job = new VelocityJob()
    43.         {
    44.             deltaTime = Time.deltaTime,
    45.             position = position,
    46.             velocity = velocity
    47.         };
    48.  
    49.         // Schedule the job, returns the JobHandle which can be waited upon later on
    50.         JobHandle jobHandle = job.Schedule();
    51.  
    52.         // Ensure the job has completed
    53.         // It is not recommended to Complete a job immediately,
    54.         // since that gives you no actual parallelism.
    55.         // You optimally want to schedule a job early in a frame and then wait for it later in the frame.
    56.         jobHandle.Complete();
    57.  
    58.         Debug.Log(job.position[0]);
    59.  
    60.         // Native arrays must be disposed manually
    61.         position.Dispose();
    62.         velocity.Dispose();
    63.     }
    64. }
    65.  
     
    pravchuk likes this.
  4. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    For generic stuff like that though, I think I'd strongly prefer Tasks. The job system only becomes interesting when they give us api's that jobs let you run concurrently that won't work with Tasks.
     
  5. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    The Job system has various advantages:

    1. It is integrated into the existing C++ job system the engine uses, thus threads won't fight each other for CPU resources
    2. There is no GC allocations anywhere in the C# job system.
    3. Scheduling jobs is significantly faster & lower-overhead
    4. It provides a more powerful language for expressing dependencies between jobs

    5. It gurantees that your code has no race conditions, this is quite unique feature and can save days. But most importantly give you peace of mind that your code works correctly which makes it signficantly more accessable

    6. When you follow the rules of the C# job system you will be able to take advantage of the burst compiler. Which gets somewhere between 5-15x speedup over existing compilers by using advanced auto-vectorization techniques.

    See this for an overview:

     
  6. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Some of that just doesn't make sense.

    - Threads don't fight for cpu, that's not how they work.
    - GC allocation, again nothing to do with jobs vs Tasks, that's an end user decision
    - Not it's not automatically faster and lower overhead. Depends on the specific approach being used.
    - Jobs a better abstraction then Tasks? I know a lot of really smart people who would disagree. In the end that is purely subjective.


    Edit: Race conditions. Yes for those not experienced with concurrency that is a good thing. But it's not really a reason for someone with experience in this area.

    I said that poorly when saying threads don't contend for cpu resources. They can in a sense although normally that's just part of your threading model. And if you are pinning threads internally to minimize context switching then I can see how using the job system could be more efficient in certain contexts.
     
    Last edited: Jan 11, 2018
  7. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    I'm not knocking the job system FYI. I just don't get why it's being promoted as such a better alternative for general purpose concurrency outside of areas where it enables concurrency for specific api's. I'd love to see some hard data on this in specific context's. Ones that aren't just using simple standard naive approaches not suited for the task. Like await, etc..

    For example I do a lot of concurrent stuff for ai with long lived threads and efficient signaling using Interlocked. Sure I have to pay attention to what I'm doing accessing stuff from other threads. But to say the job system would be more efficient at something like this generally, I don't see it. Add in more context and it could change of course.
     
  8. Singtaa

    Singtaa

    Joined:
    Dec 14, 2010
    Posts:
    492
    @snacktime I don't really understand your argument over Jobs vs Tasks. Are you suggesting an alternative implementation? If so, can you be more specific?

    AFAIK, the Unity C# Job System (along with the ECS) is an architectural shift away from GameObjects/OOP. It accommodates data-oriented design that takes advantage of the CPU cache coherence.

    Like Joachim said, "it is integrated into the existing C++ job system the engine uses". So I think this is much more optimized than async await...

    Edit: added notion of ECS
     
    Last edited: Jan 11, 2018
  9. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,609
  10. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Generalizations without context don't really mean much. Yes async/await has a cost. I'd also say it's true that if you are calling an async method enough for that to matter, in the context of Unity, you are just doing it wrong. It's not like you are going to call an async method for every granular update to something when you don't need to. No system that needs to do hundreds or thousands of things in quick order is going to funnel those individually through an async method.

    Take a simple case where you have a bunch of ai logic you want to run in another thread. In a lot of cases you just need to synchronize read access, make sure your ai logic is only reading data when that data isn't being modified in say Update. And you are say feeding decision making back to the main thread via a concurrent queue. Depending on your setup a blocking collection can work, or if things are more granular Interlocked works well.

    The point is nobody will be using async/await for this type of context anyways, it's not a valid comparison. Compare it to an actually appropriate design and the scenario looks a lot different.

    Now the job system might make a number of scenarios easier. That's the kind of thing I would have liked to hear instead of the generalizations that assumed async/await. Like if it synchronizes around the various unity events like Update/FixedUpdate, that would definitely be in the plus column. I'm waiting to see more documentation on the threading model, that's pretty much a requirement before we can really know how to use it correctly.
     
  11. Dennin-Dalke

    Dennin-Dalke

    Joined:
    Aug 10, 2014
    Posts:
    25
    Actually, this would be more the purpose of the Entity Component System, they're intimately tied, but aren't exactly the same thing.
     
    Singtaa likes this.
  12. JohnHudeski

    JohnHudeski

    Joined:
    Nov 18, 2017
    Posts:
    126
    I wish they gave us access to ECS or maybe uploaded a demo
    I was trying to recreate the Unite Demos and nothing works.
    Yet
    But still excited

    PS any eta for NativeList or NativeHashMap
     
  13. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,980
    Let me see if I got this correct, essentially the Job system lets us leverage the power of threading, but with a lot of the "dangers" mitigated due to the protections it has in place?

    If so, you have won me over again sir, because up until now threading even simple things was a nightmare
     
    Enrico-Monese likes this.
  14. angusmf

    angusmf

    Joined:
    Jan 19, 2015
    Posts:
    261
  15. JohnHudeski

    JohnHudeski

    Joined:
    Nov 18, 2017
    Posts:
    126
  16. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Memory is generally a shared resources. GC allocations in .NET performed on multiple threads in parallel slow down execution significantly, because they either take locks in mono or using quite complex lockfree structure in ryuJIT. Neither is free and both come at significant performance cost. Optimising GC allocations is definitely a way of solving it and thats what Microsoft focuses on due to their push into Server tech with .NET. Generally the locks betweens threads

    Since Unity is about realtime games, we are looking for solutions that get us optimal performance. By giving the user control over lifetime upfront (Temp (lifetime until end of job or ComponentSystem.Update), TempJob - One frame, Persistent) it is possible to get the best possible allocation performance for what you need.

    Secondly, we strongly believe that for those who really care about performance. Its important to make hard performance guarantees. If i am making a 60 FPS game, i can't afford a 1ms GC pause at unpredictable times unless I just always reserve 1ms for just that. Explicit allocations give you that hard guarantee.

    So with ECS generally it enables a way of writing code which literally causes zero allocations even while loading / unloading scenes. That is neither GC allocations, nor Persistent allocations backed by C++ engine code. This is because we allocate everything in chunks of 64kb blocks and they can be reused between totally different entities / components / archetypes.

    Well yes naturally it is very dependent on implementation. I am comparing mono ParallelTasks to Unity's C# jobs.

    We have an onboarding exercise at Unity. Where we teach all programmers to write multithreaded code. Most who come, have written multi-threaded code before. I would also claim that the programmers we hire are quite senior.

    Of around 200 of them doing our on boarding exercise only 4 have at the end of the onboarding exercise written code that had no race conditions.

    I'll also say that I think I know quite a bit about multithreaded programming by now. And I continue to make mistakes either caught by strict review or in some cases months later in the engine.

    Secondly its not even about if some dude is the super hotshot programmer who always writes perfect multithreaded code. Code evolves, and gets touched by more than one person. Often in that process information about requirements is lost and race conditions are introduced accessing data that shouldn't be accessed.


    Race conditions are a huge problem. Particularly on the asset store. Just imagine the situation where you use a couple of asset store packages, and some of them have some super rare race conditions. With race conditions its exceptionally hard to find out whose package is at fault when something starts misbehaving.

    Lastly for experienced devs, the ability to quickly refactor multi-threaded code is huge. For example for the Nordeus demo, 3 days before we showed it we were at 45 FPS. We wanted to show it at 60. We had a bunch of sync points using .Complete() calls on the main thread. We simply deleted all of them, and refactored the dependencies between jobs until the race condition checker said everything is fine. No one working on the project still perfectly knew why those sync points were there and without the ability to trust the system to immediately find all race conditions it would have been impossible to refactor the code in an evening to get rid of all of them, its just too scary and too obviously going to fail.
     
  17. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,335
    WOW! You must write a blog about that.
     
    Prodigga likes this.
  18. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,335
    About that auto-vectorization, what's the best way to write job code that processes N x 1D arrays of the same size?
    In compute shader I pack/unpack every 4 x1D array into a float4 structured buffer by hand code.
     
  19. NestorAlgieri

    NestorAlgieri

    Joined:
    Sep 11, 2011
    Posts:
    299
    How hard is it to convert an existing Unity project from OOP to ECS?

     
    Deeeds likes this.
  20. RootCauseProductions

    RootCauseProductions

    Joined:
    Feb 1, 2018
    Posts:
    31
    If you haven't seen it yet, there is a new forum for the Entity Component System and C# Job system. It doesn't look like there is too much work that needs to be done. It is mostly a refactoring of data and code into ComponentData and ComponentSystem. Another option is to use a hybrid system of new and old so you can just convert the parts of your project that are too slow.

    Remember, this is an early experimental system so I wouldn't convert anything going to production yet.
     
    cariaga and NestorAlgieri like this.
  21. buFFalo94

    buFFalo94

    Joined:
    Sep 14, 2015
    Posts:
    273
    An example based on ECS which load/unload with almost zero allocation will be greatly appreciated.
     
  22. RootCauseProductions

    RootCauseProductions

    Joined:
    Feb 1, 2018
    Posts:
    31
    That will come for free if you write your application as pure ECS and don't use any GameObjects. In the current version you still need a few GameObjects so you can't quite get there yet.
     
  23. buFFalo94

    buFFalo94

    Joined:
    Sep 14, 2015
    Posts:
    273
    Did you read the part where @Joachim_Ante says even when loading and unloading scenes?
     
  24. RootCauseProductions

    RootCauseProductions

    Joined:
    Feb 1, 2018
    Posts:
    31
    Yes, but I also understand that this is a preview and is not feature complete. Some of the parts needed to make it 100% allocation free do not exist yet. The samples available now are the closest you can get today.
     
  25. mkawick

    mkawick

    Joined:
    Feb 11, 2014
    Posts:
    8
    Threads do fight for CPU. Unity is single core so all threads fight for scheduling.
    Many things in Unity allocate behind the scenes. This necessitates the GC and performance hits. For example, in the current C# libs (3.5), Allocation happens for every packet received using AsyncCallback. Its around 600 bytes.
    Your other points are valid.
     
  26. tinyant

    tinyant

    Joined:
    Aug 28, 2015
    Posts:
    127

    Does Job system & Ecs will be used on Editor Script?