Transcript from the "Goroutines" Lesson
>> Goroutines, we're going to make an intro on this, and later, we will do the large exercises on that. So, what's a goroutine? A goroutine is the Go way of using threads. You know that every time we get into threading, it's kind of a, [SOUND] I am not sure I wanna get into that, okay?
[00:00:22] But because Go was created from scratch and was created in the modern way to solve the current problems and other problems that we used to have in the 80s or in the 90s, it's much simpler. How creating a thread works fact. Let me get out of this for a second.
[00:00:44] Because we have here the information and some samples, but let's see this in action directly. For that, I'm going to create, let me clean this up first so it doesn't have any errors. I'm going to create another version. It's going to be a simple one, not a complicated one.
[00:01:00] So, but just to play with core routines before actually using them for accessing the network. That's the next step. To use the HTTP package. So, in your project, open folder. We're going to play with Goroutines. I mean the name sounds scary, but no worries. It's actually pretty simple.
[00:01:27] So I'm going to say here again as usual you know the deal out go mode init frontendmasters.comm/go/goroutines. Now may not go with a package main and a function main. You know the deal, simple. Now, let's say that we create a function here that will say, let's say print message.
[00:02:07] That receives a message as text, And it just call format, print line, that text. But I'm going to create a for, okay? And we are going to use the for as kind of a while. Remember, also, I can use an infinite loop. Remember the infinite loop? Like so but we will see that later.
[00:02:35] Because if it's an infinite loop, yeah, we have a problem. We know we have a problem, but we can say, okay, let's start with zero 0, let's do this 10 times, okay? And then let's call printMessage That says Go is great. Okay, so nothing really fancy. I'm going to execute this and I should see go is great 10 times.
[00:03:07] Yeah, you were expecting that, nothing to worry about. So principle. So what's the deal here? What if we start waiting sometime because this is going really fast. So what if we start waiting some moments before doing something, for example, waiting a second, how to wait for something. So we need to work which we'll look for asleep.
[00:03:33] And where do we get that? Where do we get to sleep is threading. So how can we get into something like that? So if we look in the documentation, so I'm not sure if you have experience working with synchronous apps locally. Typically, you have a way to slip the thread in any language.
[00:03:57] So you ask the thread to wait. Let's wait one second, and the thread. It is blocked there for one second. It doesn't make sense, that's kind of it. So on Go, it's a time package from the standard library.sleep. The problem is that the sleep receives duration, okay, which is okay, okay.
[00:04:21] Duration in which unit? I don't know, I can see the documentation. I can get into the sleep function to see if I get any information. First is a type, it's called duration. Okay, what is the type? Let's get in, init64, okay, so it's not an alias, it doesn't have equals, okay?
[00:04:46] But it's expressing nanoseconds. Don't ask me why it's nanoseconds, but that's really precise, really high accuracy. So yeah, how many nanoseconds in a second? It's complicated, right? Anyway, so, fortunately, the time, the same time package has some constants express different units in nanoseconds. For example, hour, a microsecond, a millisecond, okay?
[00:05:20] So, also there is a second somewhere. So, I can say, okay, 400 multiplied by that will give me 400 milliseconds. Okay, does it make sense? And if you wanna read the number, you can get in. And that's how you get you can get the minute the nanosecond. Anyway, so now we can let the thread asleep for 400 milliseconds, let's say a little more 800.
[00:05:50] So now if I execute this, you can see the slowness of the code, okay? The problem is that, yeah, we're waiting 800 milliseconds but in the meantime we are doing nothing. We are not taking advantage of that time within each print us or something else. What if we wanna print another message like no, we miss classes.
[00:06:26] Okay, well, you know what will happen, let's reduce this to 5 for now. You understand what's going on, I guess. That we need to wait for the first output to end to then see the rest. So we need to wait and then do another stuff. This is sequential.
[00:06:45] It's not really optimized. But we can use Goroutine. So what's a Goroutine? A light-wave thread. It's a thread. What's a thread? Do you know what a thread? Does anyone know what a thread is? How can you define a thread? Execution thread at least.
>> Not really.
>> Not really.
[00:07:09] That's a good definition, not really.
>> [LAUGH] A process that's running.
>> A process? Yeah, well, threads are running within processes. So a thread, it's the execution line and in modern operating systems, you can run more than one at the same time. Sometimes it's, they're being executed at the same time but that's kind of a flexible definition.
[00:07:36] It depends on the west, it depends on if you're multicore, if they're actually really running at the same time or it's speaking from one or the other. Anyway, it feels like we have different lines of execution running at the same time. Well Goroutines are the way to do that here, but how that works, we just need to add Go, the Go prefix before a function call.
[00:08:08] If you say Go and you call a function, it's going to create a new Goroutine. What's a new Goroutine? Kind of a thread. It's how go, is the Go response to threading. Okay, so if I say this one, not the second one, for example, look what will happen.
[00:08:30] Just that, I don't need to create the structure a type, I just need to add Go as a prefix to any function code, any function code. So now if I run this, let's see if we can understand what's going on. So, it seems like it's doing both things at the same time, right?
[00:08:54] Or kind of, because, I mean it's not completely clear what's going on, but at least we see that it's merging responses from different messages. Why is that? First, the main function is being executed in the main Goroutine. There is always a Go routine, it's called the main Goroutine.
[00:09:18] It's the main function. Then from there, you can open more Goroutines just by adding Go, okay? Makes sense? So what happens if I want I can have more messages that say from the Masters. Rocks. And now we can see that everything is being executed at the same time.
[00:09:52] Okay, makes sense? So in this case, it's opening three apps at the same time, and from now on, one execution goes in one Goroutine, the other one goes in another Goroutine. They're using the same shared space, which may lead to some problems with memory management. What happens if one of those Goroutines is saving a value on a variable that other Goroutines at the same time trying to read the value, okay?
[00:10:18] You can lock and unlock and do things but there is a better way. There is a Go way to that. But before getting into that, go away, what happens if I add a Go to the last one because I didn't do that on purpose? You did that. What happens?
>> Nothing, and what nothing means?
>> Nothing printed.
>> Nothing printed, exactly, so let's try and see why. So if I add go there, let's see what happens, so I will clear the screen. I will run this and nothing happens. What's going on? And that leads to another question.
[00:10:57] And what's the lifecycle of my app? When my app ends? When my Go app ends? My app ends when the main Goroutine ends. When the main Go in, the routine ends when it reaches the end of the main function. Now I'm opening three more Goroutines. So I have the main goroutine and three more goroutines that they are doing their job.
[00:11:23] But the main one has nothing else to do after that. So the whole process end, okay? Does it make sense? So to prove that, let's do this. What is that? An infinite loop. We keep that main thread busy doing nothing? Let's see if that works. At least I can still see seeing the rest of the outputs and now we will be there forever.
[00:11:58] How to end up this control C, on every operating system you can interrupt Go so far with Ctrl C. But at least we understood the problem, okay, the problem is that we need to keep the main go routine busy, at least until the rest are ready because when we open a Goroutine is not a different process.
[00:12:17] It's working under my process by a different thread, if the main process ends that everything is killed, okay? We will see different solutions to this problem to avoid using these also you can sleep on the main thread, so time sleep. You can sleep but how much time? Yeah, you don't know mean so it's not like the best of the solutions, but you can say a minute.
[00:12:41] So now it will wait a minute and something like that it will work. Also but yeah, it's kind of a still not the best of the ideas. So later we will talk about if there is any way that we can create some kind of signup, we know that we know when they Goroutine, it's ending something, and doing something, and so on.
[00:13:01] But before getting into that, and by the way, if a function is calling other functions, for example, if this function, if this one is calling a So when you open a Goroutine, everything that is being executed from that line will be executed in that Goroutine. So when you call a, you don't need to add Go again.
[00:13:26] If you do that, you are opening another Goroutine, okay, so no need for that. Just to call the function, we actually continue on that Goroutine, and each Goroutine will have its own code. But have in mind that if you're accessing global variables, package variables, they are all the same.
[00:13:46] It's not creating copies of the app in memory. It just has to do with execution not with memories.