 Welcome back, everyone. This is Brian. And in this video, we're going to talk about a simple producer and consumer. This is going to demonstrate the queue a little bit better. I had some user feedback and they said, hey, I loved your video on locking threads. But you kind of said you don't like working with the queue. Can you go into it a little bit more? I don't really like working with the queue, but why not? Let's just do it. So that's what this video is really going to cover. We're going to make what's called a producer and consumer. And it is exactly what it sounds like if this is a new concept. A producer will produce some sort of work and the consumer will take that work and do something with it. But we're going to put the producer on one thread and the consumer on another thread. Let's take a look. To start off with, we need our imports. And I am going to save a whole lot of typing and we are just going to do copy and paste. I love copy and paste. Anyways, so we're going to use the random number generator threading and multi-threading because we're going to be threading these. And I want to show you which thread and which process they're in. We're going to use logging. Of course, we're configuring the logging before we do anything else from threading. We're going to import the thread class and from queue, we're going to import the queue class and we are going to stop time. We are not working with asynchronous. This is true threading. I need a basic function, something that's going to be usable by all the threads here. So I'm just going to say deaf display and we're going to is blatantly rip off the function we wrote in the last video. And if you skip that one, I'm going to type it out really quick here. We're going to get the thread name from the current thread. So I'm going to say threading dot and I want the current thread dot maybe name. There we go. Keyboard has betrayed me. And I want the process name from, you guessed it, the multi-threading current process name. And from here, it's very, very simple. I'm going to say logging and we've already configured logging by the time we hit this function. So we don't have to worry about any of that. But basically anything above debug, which means, well, everything, we want to capture that. So I'm going to say logging dot info, but format this. And I want to know the process name, we're running this all on one process. So it's kind of redundant. But I want to really know that thread name. And I want the actual message that we're printing out here. That way our logs look nice and beautiful. Now, because we're making a producer and consumer, the first thing we're going to do is make the producer. We need to actually produce the work. So I'm going to say def and we're going to create work. I want a queue. I want another queue and we're going to call it finished. And I want some sort of maximum number that we're going to get to here. Now we haven't actually created these yet. I didn't want to create global variables, but queue and finished are both going to be this queue class right here. Now queue is and somebody correct me if I'm wrong, as you often will, it is a thread safe way of getting and setting variables. So I'm going to say finished dot put. So we're going to put that out to the finished queue. I'm going to say we are not finished because this producer thread has just started. This function will be the entry point for the producer thread that we're going to be creating later. And then it's very simple. I'm going to say 4x in range, max. So whatever maximum we give it. Now I want some sort of value. This is where our buddy, the not the range, the random number generator is going to do a random int. And we want something between one and 100. It doesn't really matter what we do there. We just want some sort of value. And now we're going to take our other queue. I'm going to say queue dot put. I want to put that value out there. Let's go ahead and display something. So I'm going to set display. I want producing. We're going to say producing whatever iteration we're on and the value that we have here. Now once we're done with this, we want to shut the producer down. And we're going to do that by simply exiting out of this function. So we'll say display finished. Now we want to go back to our little buddy, the finished queue. This is a queue just like this one, but we're going to use it in a different fashion. So I'm going to say finished. And we're going to say through. So rather than storing a bull in a global variable and locking and unlocking and acquiring and releasing and all this other fun stuff, we're going to use the queue to just simply put that out there. Now that we have a producer who's going to take our queue and put some sort of value out there, we want to grab that value in a different thread. And this is going to be called the consumer. And this is going to actually perform the work. I want to say work. And we're going to use a another variable called finish, which is going to be that finished queue. I tried to keep the names very similar. Notice how I'm not putting a counter out in a global variable because then we got to use the global keyword. And then we've got to do all this locking and unlocking while true. If not work.empty. In case you're wondering what work is work is a queue. It's this little guy right here. I could have actually named it queue, but I wanted to name it work just to show you name and convention really does not matter. I'm going to say v equal work dot get. And under the hood, what happens here is our queue is going to say get the next item in the queue. Because you could store multiple items as we're going to see as we slow this thing way down here. All right, now that we got that, let's go ahead and say display f and let's say consuming whatever our counter is. And then whatever value we got out of the queue. Now I want to increment our counter because this is all in the same thread. I don't have to worry about locking and unlocking or any of that nonsense. Now, if the work is empty, I want to do something like this. I want to make sure we're not actually finished. Now remember in our producer, we have this finished queue. And when we're done, we're going to put out there a true. So I want to make sure we're actually done. I'm going to say q equal finished dot get. We're going to get the value of that finished queue. And I'm going to say if q equal true. And there's a billion different ways to do that, but I'm just going to just hard code it equals true or is true. Then we're going to go ahead and break out of here. And that'll break out of that loop. And we should let the user know we are of course finished. There's really only one thing left to do the main function. Let's stop playing around here and let's make this thing work. Now, before we really dive into threading, we're going to set some variables here. Some say max equals 50. This is going to be the maximum amount of work we want the producer to actually produce. Now we want a queue that's going to hold the work. So we call it work equal great instance of the queue class. And I want to be able to signal that other thread on a different queue when we're done. Some say finished equal queue. Let's go ahead and make a producer. This is going to be a thread and we've worked with threads before. So I'm not really going to take a whole lot of time to talk about this, but we're going to say the target is going to be the create work function. We want to give it some arguments here. Some say args equals. And we want our work queue, our finished queue. And the maximum amount of work to produce. And because we've learned a hard lesson in previous videos, we're going to set this as Damon equal true. So this thread will stop running when we stop. Ooh, all right, that is a lot of work here. So let's go ahead and let's grab this whole line. Say consumer. Now of course we need to change the target. So we're going to change this to perform work instead of create work. And we have a different set of parameters here. We have work and finish. So let's go ahead and get rid of that maximum there. That one's going to be a Damon as well. Now from here, it's very, very simple. We're just going to say producer dot start. We're going to start the producer thread. Now the producer thread has no idea the consumer even exists. So the producer is just going to immediately get up and start making stuff. Consumer. Same thing. It has no idea the producer even exists. These two threads are completely oblivious of each other. They work very independently. So we're going to start both of those. Now I want to wait on that producer. So I'm going to say join. Let's go ahead and display that the producer has finished. That way we know in our main thread something happened. Now we've got a subtle issue here. We need to now wait on the consumer. Now when we look at the consumer, if we didn't have this little bit here, this consumer will just run forever. So we want to actually have that finished queue there that we put that value in there. I mean, you could forcibly kill the thread when you kill the application, but it's a little rude to just go around killing things. So let's go ahead and say producer. Let's change that to consumer. Whoa, got a little copy and paste happy there. All right. So they can consumer join consumer finished and then last but not least, I want to know when the main thread is done. Last line of our application right there. All right. Moment of truth here. Assuming I didn't break anything. Let's run this. Whoa, that went fast. This is multi-threading at its finest. So let's deep dive and take a look. You can see immediately the producer starts producing and it's kicked out. A bunch of values into the queue before the consumers even started, but that's why I put that index there. So producing 029 consuming 029 and you can go through if you really want to, but it's first in first out. So it's going to be produce. Consume produce where is one consume one. There it is. So you can match those numbers up all day, but they're going to be identical. Now, because this is multi-threaded, you're going to see that this thing will start just plowing through this thing at blistering feet. And it's going to say producer has finished and the consumer still catching up. So now we're just consuming consuming consuming consuming. That is the producer consumer. Now, if you want to see that in action one more time, let's go ahead and clear this and let's explain this code in depth. So we've got all of our imports, which are well, pretty self-explanatory. We have a display function, which is going to show us the process name, the thread name and the message. Now, our producer, this produces the work. The first thing we're doing is saying, get a queue, we're calling it finished, and we're going to put a false in there saying we are not done. We're going to do some work. And then after we've done all that work, we're going to change that to a true. That way in the consumer, we can actually tell when we're done. While we're producing, we're going to go ahead and just update the work queue and put that value out there. And we're just going to notify the user we are producing something. Consumer does the polar opposite. We're just going to say loop forever. And then while we actually have work, go ahead and get the next item, display it, do something with it, whatever you want. And then if we're suddenly finished, then go ahead and break out of this. And last but not least, we're going to join those back into our main thread so we don't have to worry about leaking resources, crashing the application or any of that fun stuff. And the end result is well, this beautiful little dance of data. 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.