CLUSTER MULTI THREADED NODEJS -- Run threads in parallel to speed up long processes (CORRECTED)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome back to minute JavaScript right cover topics quickly and concisely but first today's video is brought to you by you and all my subscribers so a special thanks to Deepak Gareth Abdi Chirag Francisco Nick serif Nando cooled flame Fabian Yong Tao William Sam and MOX I really do appreciate you guys taking the time out your busy schedule to watch my videos and a special thanks to everybody who subscribes it really is the support of you that keeps the channel going so if you want to see more content like this please like and subscribe and now on to the show so the project I have here builds a custom gallery and as you can see here in the terminal it takes about 90 seconds to build all of the images and 90 seconds doesn't seem like a long time but it really feels like an eternity when it's running and I'd like to speed up this process so I want to implement node clustering to take advantage of my multi-core system I have eight cores on this machine and I think I could process the files a little bit faster so so I'm going to create a cluster to see how fast it speeds up this process now one of the things I've noticed already by looking at this is that even though the real time is 90 seconds it does take about three minutes 42 seconds of user time that leads me to believe that there is a little bit of parallel processing going on and I think it has to do with me running these resize images here in parallel and the reason why I think that is because the resize image library is using sharp which I believe is using some type of compiled binary probably C or C++ so the first thing I'm going to do is I'm going to pull up the documentation for the node.js cluster page their documentation actually is pretty good and this is an example I was looking for so one of the good things about their documentation is they provide an example immediately so I don't have to dig through each of the events to figure out how to do it I can just immediately look at the first example and this is exactly what I'm looking for so the way on how to use this is you import cluster at the top and so you create a fork for each of the CPUs that you have here's where they list the number of CPUs there's a node package called OS that will tell you the number of CPUs and here you can see the there's a bullying here called is master what you're gonna have is you're going to have a master process and then you're gonna have sub processes so the typical way to work in a node cluster is the the master process will set up the other child processes so there's no actual work going on in the master process it's just used for setup and you can see that's what's happening here so the code here just creates a fork for each of the CPUs and then inside of the else which is when you're not in master it's going to create the actual workload so this should be fairly easy to set up so I'm just going to import cluster into my project import cluster from cluster and what I'm gonna do is down here in my main I'm gonna wrap this in a cluster is master actually this parts going to go into the else let's comment this out for now let's just see what it looks like when it's working so what I'm gonna do is I'm going to say a console log I am a master console log I am worker and I'm just gonna run build images which execute this file and you can see here that it outputs just the I am master it never output the I am worker and that's because we didn't create any of the clusters yet so if I were to just add this line in here I should see I am master and one I am cluster I mean worker so there it is I am master I am worker okay that's working pretty well let's look at my number of CPUs I can add this here actually let's just copy all of this I'll just put this at the top we can get rid of that now I should see one I am master and I'm gonna guess I should see eight CPUs so if I open up my task manager and I go into the performance section here I can see each of my different cores and this is what I'm trying to take advantage of is that I want one process running on each of these cores so I'm going to run this one more time it outputs I am master and it looks like I have the eight workers so here's four and there's four below one thing I've noticed when using cluster is that the workers don't automatically exit so I've had to add a process dot exit and I'm just gonna hope I'm gonna add a exit code of zero which should signify that it exited successfully so I'm gonna cancel this maybe just by hitting ctrl C I'm gonna run the process again and now I'm expecting my workers to exit so here's iya master here's my workers and I'm return to my prompt which is exactly what I was expecting so the next thing I'm going to do is I'm going to add the the process ID so that I should be able to access this through just process PID and that's just so I can keep track of which worker is what I'm gonna go ahead and add this into the master as well just so we can see that they are separate processes that are all running so I'm expecting each of these numbers to be unique and I'm going to copy this because I'm going to go through my console logs so here I have a console log that says saving to file but what I'd like to do is actually include the process ID in here so that I know what process is actually saving the file and the same with error here I'm just gonna go ahead and add the process ID in here let me see if I have any other consoles and I kind of like adding it in the beginning so I'm just gonna change these and let's see what that looks like okay now let's move this block of code up one an uncomment it so I'm gonna run main first actually we're gonna have to this is perfect process out exit is already in here and I don't want to run this right now because it's gonna execute this main function for each of the processes so instead of splitting up the workload it's actually going to run the entire workload eight times once for each process so what I need to do is figure out how to split up my array here my files array into multiple arrays so that each CPU gets its own separate workload and I can do that by finding the ID of each worker so what I'm gonna do is I'm going to say the worker number here so I should be able to get this through cluster dot worker dot ID and that should give me a number of one through eight oops I actually started running it like I said I wasn't going to do and here they are and you can see the interesting thing is that the workers themselves actually do spin out of orders so there's no guarantee which order your worker is going to start you can see 1 & 2 are actually the last two workers to start so now that I know how to get the cluster ID what I'm going to do is split up the files for each cluster so I'm gonna say files and I'm gonna filter them and what I'm gonna do is I'm gonna create a filter where I don't care about the item coming in but what I do want is I want the index of that item because what I'm gonna do with the index is I'm gonna say if the index and I'm gonna use the remainder operator and here I need to have my number of clusters so I'm going to end up calling that Forks and what I'm going to do is I'm gonna take my number of CPUs here on line 59 I'm just gonna call that Forks and I'm gonna move that up to the top because I just want this to be globally available to not just this block of code here but code in this entire file so I'm moving it up here calling it Forks and I'm gonna come back down to my forks and I'm just gonna say the index with the the remainder of four hi I'm Joel from the future here to watch past me make a mistake right about here and because the future can't change the past all I can do is sit here and watch me make the mistake but I can warn you not to do the same thing in a moment I'm about to compare this to zero which is incorrect what I should have been doing is comparing it to the cluster index which would have been worker cluster ID minus one and I'm using minus one because the cluster indexed is one based so I use minus one to bring it down to zero now I've corrected the github repository as well as added the correct code in the comments so now let's return to the past and I'm just gonna say the index with the the remainder of Forks equals zero and what that's going to say is if it's equally divisible so each cluster should now get it's own set of files divisible by the the number of forks after that I can just copy cluster files replace it here I'm gonna set a breakpoint just to make sure that this is working and let's see how that goes okay and if I hover over this that's too many so if I look here I can see that files is 496 and then my cluster files is 62 so I'm gonna run build images again and I'm gonna see if this improves our speed a little bit well this is going on I guess I could bring up my CPU monitor and it looks like we're at a hundred percent utilization and all eight cores seem to be pegged at a hundred percent so this is exactly what I was hoping would happen hopefully this process finishes a little bit faster I don't know how much faster it's gonna be but we'll find out in a second okay 48 seconds so we were at about 90 seconds before so this is an improvement this is about half of the speed they'll go in from one cord eight cores expect it to be a little bit closer to eight times faster but twice as fast as okay I'm suspecting that's because there was already a little bit of multi-core processing because of the parallel processing going on here so what I'm going to do is I'm going to change the forks to one and I'm gonna run this with one fork just so that we can compare the time of the 47 seconds with how long it takes with one fork and you can see it's running on one fork because the process ID is just pegged at 7000 391 I should bring this up too so I can see that my utilization is a little over 50% looks like we're hovering between 50 to 60% you can see each of the CPUs dude a little bit of processing so there is definitely some type of multi-core processing going on but it's not utilizing all of the CPUs so again yeah we're at 138 so it is about twice as fast so I think maybe spreading this load out to the eight processors isn't very efficient so I'm gonna try and just increase this to two and see if I can get the CPU monitor to pay get a hundred percent that's that's kind of the goal here is the to use the minimum number of cores that that maxes out the CPU so it looks like I'm at about 95 percent which is not what I'm looking for I want 100 so let's change the forks again to from 2 to 3 and see what this does 100% CPU okay so this is good news so I don't need to I don't need to actually go up to the full 8 I think forking 2 3 processes is gonna work I don't know if this will actually save any time but I guess we'll find out at the end of this run 52 seconds so it's about the same speed it was 47 seconds before versus 52 seconds before I'm gonna go ahead and chalk up those extra five seconds to variance I think if I were to run this a couple of times and average out the numbers I'd probably find that the difference between three cores and eight cores doesn't make that much of a difference so I'm just gonna go ahead and leave this as three I'm gonna leave this comment in here just in case I decide to go back to two more cores so now it's a recap all I had to do was import cluster at the top set my number of Forks that I wanted to create you can go ahead and create one fork per CPU in my instance 3 was fine on an eight-course system so I went ahead and just hard-coded that you have to check to see if your cluster is master because you only want to run cluster dot fork one time just when the program first starts so master is going to start it's going to run a fork for each of the Forks that I have set after that once these processes run each of the Forks is going to run inside of the else instead of because it's not the master and it'll it'll fire up this main process so that's why it's always good to have your code bundled into some sort of main function I'd actually go a little bit further if this wasn't a personal project I'd move all of this code here in main out into a separate file and I'd have this entry point be just the the spinning up of the cluster and then I would import it but because this is just a pet project having all the code jammed into one file isn't bad and then of course in the file you have to make your content cluster aware another interesting thing is that by running by running this multi-core it did save about 50% of the speed but it wasn't an 8x improvement in speed so while 50% is still a significant improvement again your your miles might vary based on the type of project that you're trying to do this on and that's all it really takes to setup clustering on nodejs it's fairly simple the docs are straightforward if you want to check out the project that I've been working on there's going to be a link in the description and of course if you've made it this far like subscribe and share it with a friend and co-worker every little bit helps me out and I do appreciate it thanks and I'll see you in the next video
Info
Channel: Joel Codes
Views: 10,628
Rating: undefined out of 5
Keywords:
Id: hXb95jm-kk0
Channel Id: undefined
Length: 15min 28sec (928 seconds)
Published: Sun Jul 12 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.