 Welcome back everyone. This is Brian. In this video, we're going to look at how to move a function to multiple threads and we want to wait for all of those threads to complete. So let's dive in and take a look. Okay, the beginning step of pretty much any application is imports. What are we going to be using? Now in the future videos, I may just copy and paste these just to save time, but because we're still technically in newbie land, I want to slow down. So we're going to import logging. So we're going to log to the screen. We've covered that in a previous video. And then we're going to import the thread class, but threading is a big module. So I want to import just the thread class. So I'm going to say from threading import thread. And I get a lot of questions about why wouldn't you just say import threading? Well, you can it's just going to take a little bit more time and it's going to use more resources because you're importing the entire module rather than just the one class that you need. And we're going to go ahead and say import time. Time has a special function called sleep, which puts the current thread to sleep. Now when we say current thread, we're talking about the current thread that's running. The main issue with multi threaded programming is you can have multiple threads running at the same time. So current thread really talks about which one you're currently focus on, or the one that's currently running, say import random because we're going to work with the random number generator. The next step is we need to make our function that's going to actually perform the work. Now this function is just a normal function. We can call it on the main thread or on separate threads is really no special magic to this. Now I want to kind of just have us take a nice leap of faith here because we're going to set up logging in the main function, but we're going to use logging in this function. So I'm going to call this long task. And let's give it a name. And we're going to say max equals and what random dot random range, this is going to make a random number between a range of two numbers. Covered this in previous videos, but just in case we missed it, and we're going to say logging. Now we haven't set up logging yet, we're going to do that the main function in the next segment. So just leap of faith time, we're going to just assume that logging is set up by the time this is called. I'm going to say info. And then I want to format this. I want to say task. I want to print out the name. That's the variable, or I should say the parameter that we got sent here. And then let's go ahead and say performing. And then we want to know how many times we're going to be performing this work. So I'm going to convert that to a string. Max really don't need to convert it to a string, just showing that we can do that. We're going to do this X number of times, or I should say the maximum number of times here. So what are we actually going to be doing? Well, for X in range. Oh, if I spelled range, right, there we go. Max. And then we're going to log. Go ahead and do that in a format. And we're just going to simply say, task, and then whatever our name is. And then we want to just print out X. This is where things get a little bit interesting. So far, this function's really not super complex, but we're going to introduce a stumbling block here. We're going to say time, sleep. And this is going to put the current thread to sleep, meaning it's just going to stop functioning. If you were running this on the main thread, it would appear as if your application has completely locked up. I know you've seen this before when an application becomes unresponsive. We're going to simulate that using sleep. And this is really the main reason why you would use a thread is some sort of action that's going to take a really long time. And we're going to say random. And we want to a random range. We're just going to simulate some sort of activity. And anywhere between one and three seconds, we want this thread to go to sleep. Now I have to say when this thread goes to sleep, because we don't know what thread we're calling this on. Let's go ahead and just say logging dot info. I'm going to format this and we're going to say ask whatever the name is complete. That way we know this is now done. So how do we know what's going on here? Well, when we jump into the long task, we're going to have some sort of range here between one and 10. That's going to be the number of times that we're going to loop each and every loop is going to put the current thread to sleep. Meaning that current thread is going to just stop working for a random number of seconds between one and three. This is going to simulate long activity or make it look like the application is crunching a lot of numbers. Okay, let's go ahead and do our main function here. So I'm going to say, let's say main. Let's see if IntelliSense will help us out. It will make a main function here. Now I'm going to do a little bit of copy and paste just because, well, we've done this before. So there's really no sense in you watching me type this out for 10 minutes straight. So I'm going to copy and paste our logging config. And if this looks big and ugly, it's because it is. Remember, we've covered logging in a previous video. We have to do the basic config before we do anything with logging. Otherwise, it will ignore the config. We're going to format that as the level, the time, the message. And we want to specify the date format for the time into hours, whoops, hours, minutes, seconds. We also want to set the logging level being a little tricky there to debug. So we're capturing pretty much everything. Modify that as you need. But I wanted you to be aware of what's going on there. From here, I'm just going to say logging dot info. And let's go ahead and say starting. And I want to wrap this up with this right here. Finished all threads. The basic premise meaning we're going to do something here. And that do something here is going to take a very long time. So we want to push that off to multiple threads. So for example, if we were to take our long task here, let's just call that main. And let's run this see what happens. So you can see it's taking a long time. It's going to do that eight times and it's just taking forever. This is called a single threaded application. We haven't done any threads, but we do have one thread and it's the main thread. That's what's called a single threaded application. And that's why some apps are very slow. And that's why people want multi threaded applications. So we're going to go ahead and comment that out. And now we're going to run on multiple threads. And it's not really as hard as you think it would be. I'm just going to say threads equals and we're going to make a list of threads here for X in range. And we want 10 threads. I'm going to say T equals and we want to make a thread. And in the thread, we want to specify a few things. So we want to specify the target. And the target is quite simply just the function the thread is going to run on. We're going to call the long task function, which we created. Now we want to give it some arguments. I'm going to say args. I always love that word args. Sounds like a pirate. We're going to give it a list. I'm going to say thread. And let's go ahead and give it a string representation of X. Let's say thread and then whatever X is. Now we want to go ahead and say threads dot append. And we're going to add that to our list of threads. And of course, we're going to start each individual thread. So I'm going to say T dot start. Really? That's it. It's not super hard. So let's go ahead and clear this out. And let's run this and see what this looks like threaded now. You can see it goes much faster and we can see some completes in there, which means now we see the actual individual threads completing and we can see, you know, zero, one, six, all these individual threads are firing off and each one's going at random intervals. We have a subtle problem though. Our applications running even though when we look at this logging info finished all threads, we want to wait till the end. And if we scroll up here all the way up, you can see it fired off. Well, about a quarter of the way into it. So we got starting some threads kicked off and then finished all threads. So how do we actually wait for all these threads to complete? We're going to use something called join, which is a lot like joining a meeting. You know, you ever sit in a meeting and you just kind of wish you weren't there. Well, that's exactly what we're going to do. So we're going to say, wait for all threads to finish. This is why we put them in a list to begin with. So we're going to say for T and threads T join. We're going to say, hey, you know what, thread, you're off in thread land doing your own thing. I want you to come back and join the main thread or more specifically, it tells the main thread to wait until that thread's finished because we're doing this in a loop. We're saying wait until all of the threads are finished. Go ahead save. Let's clear this out. Let's rerun. And we're just going to wait just for a second. And what do you want to talk about while this thing's running? I don't know. I like coffee. I like my coffee black. Some people say only psychopaths drink it black, but I really like black coffee. I just can't get into like cream and sugar. Hey, there we go. All right. Enough of a coffee conversation. You can see finished all threads is the very last thing. So yes, this did work as expected. So if we scroll up and I'm actually going to just pull this all the way up here. You can see starting and then we are firing off and right away. The threads are firing off. So you got zero, one, two, and then so on. And then you can see each individual thread is spinning up each individual thread is working. So like we have thread zero, one, two, three, seven. Notice how it skips right there. This is really the cool feature about threading is you're going to create these threads and the operating system is going to decide what to do and how to do it. And then it just works and it just goes and chugs away at these numbers. And you can see that it's all kind of haphazard and out of order. And it's because each thread is working independently at the very end of this. We're calling join on all those threads because we want to wait until they're all done. And we get this very final finished all threads. That is how you would join everything back together and you would know that all of your threading is done and you can continue back on a single thread. I hope you enjoyed this video. You can find the source code out on github.com. If you need additional help, myself and thousands of other developers are hanging out in the Voidrealms Facebook group. This is a large group with lots of developers and we talk about everything technology related not just the technology that you just watched. And if you want official training, I do develop courses out on udemy.com. This is official classroom style training. If you go out there and the course you're looking for is just simply not there. Drop me a note. I'm either working on it or I will actually develop it. I will put a link down below for all three of those. And as always, help me help you smash that like and subscribe button. The more popular these videos become, the more I'll create and publish out on YouTube. Thank you for watching.