Playing
08. Concurrency

Transcript

00:00
If you found yourself running multiple slow running tasks, then you'll love Laravel's concurrency functionality. What we're going to do in this episode is take a look at a demonstration of what this solves.
00:11
We then of course can dive straight into how concurrency works. We're going to look at some of the options that we can add to this. And then at the end, we're going to look at a warning of probably when you shouldn't use this. Okay.
00:23
So to start with, let's mock out two longer running processes. So for example, let's say that to assign a variable, which of course wouldn't be the case, this took about three seconds. Just imagine that this is a class that does something within your applications.
00:40
I'm just going to add a PHP sleep in here for three seconds, just before I assign this value to this variable. And then I'm going to do the same thing down here. And we're going to do this for the second value.
00:52
So just imagine these are two separate classes that run some sort of action or their database queries. Now, if I go ahead and die dump both of these, what do we think is going to happen? So let's die dump first and second.
01:05
What we're going to end up with when we run this is a total of six seconds delay, because for this single PHP process, we're going to have to wait three seconds for this first variable to be assigned. And then another three seconds for the second.
01:17
And then finally, after six seconds, we'll get to the point where we dump this. So if we go ahead and refresh this just in the browser, we wait about six seconds. And then finally, we get these two values dumped out.
01:28
Let's go ahead and pop this exact functionality into Laravel's concurrency functionality and see how this changes. So we'll get rid of this. And let's go ahead and use the concurrency facade.
01:40
So let's go ahead and pull this in. And we're just going to say run. What we can do is inside of an array, create out as many closures as we need that are now going to be run concurrently.
01:51
So let's just do this with a long closure for both of these just to start with. And then we'll switch this up. So I'm going to go ahead and do exactly the same thing as we did before. But this time, I'm going to return first from this closure.
02:05
And then we'll create a second closure down here. And we'll do exactly the same thing again as we did before. So we'll sleep for three seconds and we'll return second. Now, when we run this, what's going to happen is
02:18
both of these closures are going to be serialized. They're going to be sent to a background artisan command, a CLI command, which will allow them to run in their own process at exactly the same time. Once the longest running thing in this list of closures that we're running finishes,
02:39
the entire result will be returned to us. So let's just go ahead and run this. And then we'll figure out how to get these values back. So I'm going to run this.
02:47
And we normally wait about six seconds. Now we're only waiting three. So you can see that only took a few seconds to run. So both of these things are now running concurrently.
02:58
So how do we get these values back? Well, they're just returned to us as an array in the order that we passed them in. So we can just easily extract these out with first here and second here. And then just down here after this has run, we can go ahead and grab both of them values.
03:15
Let's go over, give that a refresh. We wait about three seconds because these are running at the same time. And we get both the values back. You don't need to extract these out.
03:23
You can always go ahead and, say, pull back the entire thing that you're trying to get back. So you could just go ahead and dump the entire thing. And of course, because of the way that we've extracted that out, this is just going to be returned to us as an array like this.
03:38
So it depends on how you need this data back. So to be honest, that's pretty much it. But let's just dive a little bit deeper of how we can use this, first of all, in a more practical scenario.
03:48
And second of all, how we can configure this. Now, particularly when you're running tests, for example, or you're in a different environment, you probably don't want this to actually work concurrently.
03:59
There might be tests that you have that rely on this data being executed in a normal sequential manner. That's absolutely fine. What you can do is you can change around the driver that's used.
04:12
So we have three different options. We have process, which is the default. So that's what we've been using. That will put that into a CLI process for us and run concurrently.
04:22
We also have fork, which is good for CLI commands specifically. And you get more performance this way. And we have sync. And you might have come across sync before in other Laravel configuration options.
04:34
This will just do nothing. It would just run these one after another. So if we were to run this with the sync driver, you'll notice that we get a six second delay.
04:43
Now, it's not always appropriate to go ahead and specify this using the driver here, unless you have a good reason to. So what you can actually do is you can go ahead and publish the configuration for this. So if we say PHP artisan config publish concurrency,
04:57
that's going to go ahead and create a really simple concurrency config file, which just gives us the concurrency driver. So you can either specify in here or probably more appropriately for different environments, you could go ahead and just add this to here
05:11
and say that you want to process perhaps on your local machine and production. And then maybe when you're testing, you might want this to change over to sync. So you can change that up based on your environment. So concurrency is really good for long running tasks,
05:26
but you need to be really careful here. Let's take a look at an example of using some short closures to just grab back a couple of counts from the database. So let's go ahead and change this up to grab a bunch of users,
05:37
but also a bunch of deleted users as well. Just imagine that in a controller, you're grabbing all of the users in your application to list them out, but also the deleted users using soft deletes.
05:48
I've already got this set up over on the user model with the soft deletes trait, and I've added that to the database as well. So we can grab both of these back. So let's go ahead and build this in,
05:57
and then we'll look at the speed difference between doing it with concurrency and without just to show you that concurrency probably isn't always the best option. So we're going to return from here using the user model, just the count of all of the users in the database.
06:12
And then for the second closure, again, you're just using a short function here. We're going to go ahead and say user only trashed, and then we'll grab the count of them. Or we could just grab them all and then count separately.
06:25
So just say get here and get here. The idea is we're doing two things like running a query concurrently. OK, so let's go ahead and just die dump on our users, deleted users, just to make sure these are coming back.
06:40
And there we go. So we've got a thousand users who are just standard and then 47 who are deleted. Let's bring this into an example with a view so we can see the speed difference between these. So let's go ahead and make out a view called home.
06:54
Let's return that view from here, home. And let's go ahead and output both of these values and deleted users. And over in home, let's just do nothing in here. But we are going to go ahead and pull in debug bar.
07:08
So let's go ahead and pull debug bar in and see what happens here. Now, as we've already explained, both of these closures are going to get serialized, pushed to an artisan command and run in the background in concurrency. So what that means is if we were using something like Laravel debug bar,
07:24
we wouldn't actually see the queries here because these are being executed in the background. I will actually bring these into the view just so you can see that this does work. So let's say users count. And let's say users deleted count.
07:38
And let's head back over and you can see that that does work. The queries look like they've disappeared now. OK, so look at the memory usage here and look at the request duration. So we've got a 16 megabyte memory usage and we've got a request duration of 193,
07:52
sort of on average around 180. Now, let's look at doing this the standard way. So why don't we just take both of these queries and just assign them down here. So we'll just say user and get.
08:04
And we'll just do a similar thing here to deleted users. And we'll say only trashed and get. Let's comment out where we're using concurrency to grab both of these together. And let's pass these down.
08:18
So if we give that a refresh, you can see that this request is actually much faster. So just by using concurrency, this doesn't mean that you're always going to speed things up. Concurrency is good if you have very long running things that you need to group together. So as an example, you might have a concurrency set up to generate some reports.
08:41
So you might do something like generate user report and run and generate another report run. These on their own might take, say, three or four seconds each to run, in which case you would want to group them together if they didn't depend on each other. And then you're going to see a speed advantage.
09:00
It's probably not a good idea to group things and run them concurrently that really don't make that much difference when you just run them normally like this one after another. So with Laravel's concurrency, any tasks that you need to run concurrently that do not depend on each other,
09:16
you can easily now run these in completely separate closures which get serialized, push the back end, run individually, and then return straight to you. Just be careful of what you use it for and make sure you're always checking the speed of these to see if you actually need it or not.
26 episodes2 hrs 34 mins

Overview

Need to know what’s new in Laravel as it happens? Every episode of this course is dedicated to covering the most interesting and useful Laravel additions in detail, so you’re ready to start using them in your applications.

Check back often, and stay completely up-to-date with Laravel.

Alex Garrett-Smith
Alex Garrett-Smith
Hey, I'm the founder of Codecourse!

Episode discussion

No comments, yet. Be the first!