Async Techniques and Examples in Python Transcripts
Chapter: Leveraging CPU cores with multiprocessing
Lecture: Demo: Scaling CPU-bound operations with multiprocessing
0:00 Here we are in our multiprocessing demo chapter.
0:03 It might look familiar, actually.
0:05 Remember this? Computed and computed_threaded?
0:07 Where we did this math, especially the computed_threaded.
0:11 We figured out how many processors we had
0:13 and we said we're going to take this math function
0:15 and we were going to run it across all of these
0:17 operations, but we're in fact going to break
0:19 it into a bunch of segments and have it work
0:22 on each independent section.
0:24 We saw that with the threads, that was super underwhelming.
0:28 Let's just really quickly review that.
0:29 I'm going to call this function called do_math()
0:32 and it's just going to do a bunch of wasted computational stuff
0:35 for a certain period of time.
0:38 So the details aren't super important
0:40 but our goal in this section is to stop using
0:44 threads and start using multiprocessing.
0:47 Okay, so let's just take this threaded example
0:50 carry forward with it, so we're going to say
0:52 compute multiprocessing, set that one to run.
0:58 And it'll do threaded stuff for a moment
1:01 doesn't matter, we'll come back to it.
1:03 So our goal is to replace this thread stuff
1:06 so right now what we're doing to our threads
1:07 is we're creating the threads, and then we're starting
1:09 them and then we're waiting on them.
1:11 So what we're going to do is stop using threads
1:14 and we're going to just focus on multiprocessing.
1:17 Now we're not actually going to need this
1:20 instead, what we're going to do to make this
1:21 a little bit simpler is we're going to create
1:23 this thing called a pool, so I'll call.
1:25 Pool is going to be a multiprocessing.pool
1:28 we can set a couple things in here.
1:30 For example, we could set how many processes
1:33 we'd like to use, now if we don't see any
1:36 if we say nothing is going to use processor count actually.
1:40 So we can just leave it like this
1:41 that's probably what we want.
1:43 You may want to constrain it to have fewer processes
1:45 than it has processors, and similarly
1:47 you might have even more.
1:49 So what we're going to do is we're going to go to the pool
1:51 I'm going to called a function called apply_async.
1:53 Here we go, and what does it take?
1:55 We have to pass the function, so it's a little
1:58 bit annoying that the signatures different.
2:01 Do not know why, but we don't have a target
2:03 we just have the function that's not named.
2:05 So we say do_math, and we'll call it
2:07 and then we have the arguments.
2:09 Which is, again, going to be that.
2:12 And that's it, so this is going to actually
2:14 start to work, we don't need to call stark.
2:17 And how do we wait, well, we're going to say
2:19 pool.close to tell it that no more work
2:22 is coming, so when its processed all its work it can quit.
2:24 And then we're going to, just like we did on all of
2:27 the individual threads, we're going to join on this.
2:32 Clean up on the formatting there
2:34 okay, I think that that actually might do it.
2:37 Not sure we could do anything different.
2:39 What did we do? We didn't put our threads in the list
2:41 and then managed the list, we're just calling
2:44 pool.apply_async, we're using the number of processors
2:47 on this machine by not specifying
2:49 any particular number here.
2:51 Let's go, let me run the threaded one one more time
2:55 so just to, let's run the single threaded one.
2:58 Just see how it goes, remember it was around 7.5 seconds.
3:05 7, 7, 7, how is our multiprocessing
3:08 going to do compared to this? Let's give it a shot.
3:11 It's running, it's done. Yes, that is what we wanted.
3:15 Is it as fast as if we had multiplied it or divided
3:18 it by 12, a factor of 12 x increase.
3:21 I don't think so, let's find out.
3:24 No it's about five times faster.
3:26 We are starting separate processes and all of that.
3:30 Still we've seen a dramatic, dramatic increase
3:33 in performance, we went from 7.8 seconds
3:36 to 1.4 seconds, and you saw how much code
3:41 that actually took.
3:42 It's a lot of talking and explaining and so on
3:44 we're actually turns of rewriting this loop
3:46 it's ridiculous right?
3:48 We created a pool, did a calling thread
3:50 and then start, we just called pool.apply_async.
3:54 Pretty much the same arguments and off to the races we go.
3:58 Let's just look at this really quick.
3:59 In my little glances program.
4:02 Okay, here you can see not a whole lot's going on.
4:04 CPU is around 6%, this is not going to run long enough
4:08 for interesting things to happen.
4:10 So I'm going to make it a little bit longer
4:12 ten times longer, so we can run it for 10 seconds
4:14 and see what happens.
4:17 Now if we watch, what's the CPU usage?
4:19 Woo, it's 96% of the entire machine, 99.
4:24 Remember I'm doing screen recording
4:25 that probably knocks out one of the CPU's right there.
4:27 And look at all of these python processes.
4:30 Heres the multiprocessing happening.
4:32 So they're all running and they're cranking along
4:35 and then boom, they're done.
4:37 They're all finished and now we're just down to my one
4:39 little python app that's sitting here
4:41 or something to that effect.
4:43 So there we go, it took 14 seconds
4:46 because we made it 10 times as much so it's pretty much
4:48 a linear scale right there. Awesome, awesome, awesome.
4:52 So a multiprocessing really quite easy to use.