Unity Job System — A Practical Code Example

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Unity's new high-performance multi-threaded Dayna oriented technology stack or unity dots for short is a complete solution that enables you to write highly performant game code with ease at its core it's made up of the c-sharp job system the entity component system and the burst compiler and using all three will grant your game performance by default but it'll also lock your project into a framework that will require not only a shift in your workflow but a complete change to how you approach game development in unity No that's intimidating and I don't blame you decide to hold off on rewriting your entire project in order to use this amazing technology but it doesn't change the fact that you might need to optimize your code right now so is it possible to use just a part of unity dots well in this video that's exactly what we're gonna explore we're gonna take a game with some CPU intensive logic and try to improve its frame rate using only the c-sharp job system that's because unlike the entity component system piece of unity dots the job system does not require a wholesale change to your project structure we should be able to download it add a few lines of code and get some major improvements to performance but before we do that my name is Charles and this is infallible code a channel designed to help you become a better game developer if you'd like to learn more about unity programming and game development then be sure to subscribe and don't forget to hit that Bell icon in this video we'll be optimizing a city simulator similar to city skylines which is a game that's pretty well known for being CPU intensive if you're following along and I highly suggest that you download the example project and do know that I'll be using unity 20 1933 f1 and there might be some slight differences if you're using another version when we press play we can see that besides a few ships flying around there doesn't seem to be much happening in the scene but for some reason the framerate is hovering at around 15 brains per second let's see if we can use the profiler to find out why let's open it up by clicking window expanding the analysis submenu and clicking on profiler now the problem we're facing is that each frame is taking a relatively long time to process that's why our frame rate is so low as a point of reference in order to achieve 60 frames per second each frame will need to take less than about 16 milliseconds to process if we click on a frame to pause the scene we can see that each frame is taking about 60 milliseconds to process which is over double and explains the thirtyish frames per second that we're getting now we should be able to find out why using the timeline section at the bottom of the profiler window this highlighted region represents the frame that we paused on and this blue bar which is actually separated into chunks represents the length of time that our code takes to execute clicking through them it's clear to me that the issue lies with the update method of the building class but not that the logic itself is inefficient but that there are so many instances of building in the scene in fact there are over 50 of them and every single frame each one of them has to wait it's turn to execute on the main thread if only there was a multi-threaded solution in unity that way all the buildings could run their logic at the same time on their own separate threads well luckily for us there is and it's called a c-sharp job system unity c-sharp job system is a package that allows developers to write multi-threaded code which can provide significant gains to your games frame rate and when coupled with the burst compiler c-sharp jobs have improved code generation quality they can result in a substantial reduction of battery consumption on mobile devices sounds pretty good right let's add the package to our project and see what we can do with it back in unity click on window and then package manager then because at the time of this recording the job system is still in preview click on advanced and make sure that show preview packages is enabled now we could search for the jobs package and click install beautiful with that out of the way we can finally switch on over to the code here we have the class that's causing all of our problems the building class it has a serialized field called floors that we can set in the editor a private member variable called tenants that's calculated in the awake function and a property called power usage that gets updated in the update method and as presumably used elsewhere in the simulation now again the issue isn't with the code itself but with the fact that there are so many instances of this class running in the scene which is why we're gonna try to Java Phi it so that all the buildings can update themselves at the same time or at least as many of them as possible in multiple chunks first thing we'll need to do is create a job let's do that now above the Declaration of building we'll call it the building update job all right so a couple of things to note one our job is a struct that's because the job system doesn't support strongly typed classes this is an important restriction because it gives the job system complete control over how it stores objects in memory which as you can imagine is as optimally as possible next you'll notice that a job implements the ID job parallel for interface this is one of a handful of interfaces that can be scheduled to run on one or more threats we're using i job parallel four because it can run the same logic over a list of items which is exactly what we'll try to do with our buildings now we'll need a place to schedule our new job so let's create a model behavior called building manager and give it a list of buildings then create a new instance of the building update job in the update method and make a call to schedule this will get the job running we'll need to pass in a value for length which represents the number of items this job will iterate over and batch count which represents the size of each threaded batch let's use the size of the building list and one perfect finally we'll need to ensure that the job finishes its work before the next frame which we can do by calling complete on the job handle object that's returned by the job's schedule method alright so we've created and scheduled our job but it doesn't really do anything it needs to calculate the power usage of all the buildings but we can't pass those buildings in because the job system doesn't support strongly typed classes to get around this I think we'll need to encapsulate all of the code that we want to job if I into a struct so let's nest one inside of the building class we can call it data this will give us a little bit of syntactic sugar later now we just need to migrate all of buildings data which consists of the tenants and power usage field I think we should leave floors and building though so we can continue to change it from the editor luckily because data is nested within building we can still reference floors inside of its constructor to initialize tenants like we were doing in the awake method perfect lastly we can migrate this update method and clean up the building class awesome now we can reference our new struck inside of the building update job will do that by adding an array of data objects for it to iterate over again you'll notice I'm using this native array object instead of the standard c-sharp array and that's because this is a special type of array that was designed to work optimally with a c-sharp job system but don't worry because it works just as you'd expect first we'll grab a reference to the current building data object based on the index then we'll call its update method and finally this is really important we'll pass the data back into the array at the same index which is another small quirk of the job system we can't just use an index reference we need to explicitly pull the object out of the array do our work and then put it back in next we need to update the building managers creation of its building update job to include a building data array based on its list of buildings from the scene so let's create an instance of a native array and pass in the size of the building list as its length we also need to let the job system know how long we need this list to live in memory which we can do by passing in an allocator we'll go ahead and use the temp job allocator since at the moment we're only using this list for one frame within a single job now we can populate it and pass it into the building update job beautiful the last thing we need to do is dispose of the native array we told the job system that we only needed it for this temporary job so let's call dispose right after the job completes all right we're just about ready to test this out but first let's clean this up by moving the building manager class and building update job struct into their own files much better now back in unity let's wire all this up first add the building manager to the parent of all of our building game objects then lock the inspector in place and drag all of the buildings into the building's list and that's it let's run the scene uh-oh looks like we're getting an exception randomrange end can only be called from the main thread ah I know what this is another small adjustment we'll need to make for the job system let's pop back over to our building data struct as we can see it calls the static random class inside of its constructor and update method which of course isn't supported by the job system but that's ok because the jobs package comes with a special mathematics library that was designed for this exact scenario let's add a new field that uses the random struct in that library then initialize it in the constructor with a seed of 1 for now and then replace our two calls to the static random class the method is a little different but yields the same result great back in unity let's run the scene awesome that solved their problem so now let's take a look at the profiler and see if her Java vacation actually worked pausing on a single frame the performance is already looking much better if we zoom in we can see that the building manager is in fact scheduling the building update job and if we scroll down to examine the job section we can see how the work of that single job is spread across all of the available workers so for all intents and purposes we did it we use the job system to leverage the multi-threading capabilities that are available in unity without changing the entire structure of a project but I think we can do just a little bit better back in the building manager class we can see that all of this work is being repeated frame after frame in the update method but we can optimize this further by instantiating both the building update job and building data array inside of the awake method let's do that now by introducing fields for these two objects and then moving their instantiation logic into a wake of course now we'll need to modify how we allocate and dispose at the native array so let's change the allocator to persistent and call it's disposed method in ondestroy instead of update all right looks good I feel like this is more robust and something that we'll be able to iterate on a little bit better in the future let's take a first Bend great works like a charm that seemed to work out pretty well of course there are other considerations to be made like how do we relate the new power usage data back to its respective game object we could potentially use a dictionary or maybe a generated ID but that's a consideration for another time in fact again I encourage you to download the project follow along with the video and see how you can iterate on the code but I guess the important takeaway is that you don't need to lock your entire project into unity dots to get multi-threaded performance as we've seen with this small example you can leverage this powerful technology on a case-by-case basis I'd love to hear your thoughts so feel free to leave a comment below or join our growing community of game developers on to schooler or we can discuss this topic a little bit further thanks for watching and as always I'll catch you in the next video a special thanks to my top supporters Bergquist 3d dark rush photography bar star Thomas Trond Jakub al Safari and iron Alex [Music]
Info
Channel: Infallible Code
Views: 60,967
Rating: undefined out of 5
Keywords: Unity Job System, job system unity example, unity dots example, Job System Unity, unity job system example, unity job system without ecs, unity job system demo, unity3d dots, Unity3d dots example, unity multithreading, unity multithreading example, unity multithreading c#, unity multithreading tutorial, Infallible code
Id: 3o12aic7kDY
Channel Id: undefined
Length: 13min 49sec (829 seconds)
Published: Sun Mar 08 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.