Home
Sign in Buy now

Golang Language Fundamentals

Go routines and channels

Completed

Summary

In this episode, I introduce Go routines and channels as Go's approach to concurrency, allowing multiple functions to make progress simultaneously. I demonstrate how to create go routines using the `go` keyword and explain how channels enable communication between go routines and the main program through blocking operations. I show a practical worker pattern example where multiple go routines can process data chunks independently, though I note that most web development tasks won't require direct use of go routines since many packages already handle concurrency under the hood.

Transcript

I want to briefly introduce you to the concept of go routines and channels. We're not going to be using these, at least directly in the course, but they are important to know about and understand. So the way you can think of go routines is that they are Go's way of running multiple functions at the same time. While this is not technically correct—concurrency is making progress on multiple functions at the same time but not necessarily in parallel—this really depends on the environment you operate in. Do you have a single core versus multi-core CPU? But it's a good mental model to start with. So now I just want you to think of go routines as running multiple functions at the same time. Let's take a look at a quick example. Say we have a function here called `sayHello` and it simply just prints out a message "hello from go routine". And then down here in our main function we can turn this function into a go routine by adding the `go` keyword and say `go sayHello`. And beneath it let's just print out something like `println("main function done")`. Now if you were to go and run `go run main.go`, you might see "hello from go routine" or you might not. It really depends on whether the main program finishes before the go routine. If the go routine finishes before the main program, it will succeed and print out the message. But if the main program finishes before the go routine, the go routine will get killed and we don't see any output. So what we need here is a way for our go routine, or go routines in plural, to communicate with the main program. And this is where channels come in. So above our `go sayHello` call here, we can make a channel. Let's just call it `ch` for channel, short for channel. And then we make a channel by saying `make(chan string)`. You can use other data types, but here we're just going to create a channel that carries strings. Then down here in our go routine we can say `go func`, and then in here we call the `sayHello` function, and finally we're going to write some data to this channel. And right now we're just going to write an empty string. Finally we can down here say `<-ch`, which just means reading from the channel. So what have we done here? Well, we have created a channel that holds things, and then in our go routine we send data to that channel using this arrow notation, where the direction of the arrow determines the flow of information. So in our go routine we send data, and then later on we receive data from that channel. And when receiving data from a channel, the program or the main program will stop and wait until the data is available, which is also known as blocking. This is especially useful if we have something like, let's say, a worker process that takes some data, does something with it, and then returns it again. Being able to spin up multiple workers that can independently work on a piece of data is very beneficial when we have large amounts of data that we can split into chunks. So let me just show an example here. Create a new function called `func worker` that has an `id` and then it accepts a string channel. Inside we will just have a `result` that is literally just going to be a string: "this is worker" and we're going to use the `id`. "Finished" there we go. And then we write that result to the channel. All right, so before here we just had one go routine, but we can spin up as many as we like. So instead of doing it directly like this, we can use a loop and say `for i := 1; i <= 3; i++` run the loop. And then down here we simply `go` run `worker` as the index and then the channel. Right, then we can also collect the result from these three workers where we're going to be saying `for i := 1; i <= 3; i++` we increase it, and then we just grab the result from this channel using this arrow notation, and then we can print it out: `result`. There we go. So here we spin up multiple workers, we print out the result. We would in a real scenario do something with the data right before we return it, but this is a very simple illustration of how you can spin up multiple workers and then sync them and then do something with the result as it comes in. For most tasks that you're going to be doing in web development, you wouldn't need to reach for go routines. Some of the packages that we will be using already have go routines under the hood. For example, our router will use them to concurrently handle incoming requests. But generally you need a large amount of data before go routines really become beneficial.

Episode Notes

Get the Full Course

Unlock all episodes and get lifetime access to course updates.

What others say

"With this course, I'm learning Golang + datastar while building my personal blog hitting several birds with one stone. It's a fantastic course."

Testimonial from ignacio
Ignacio Barceló
Bought Early Access

Video Completed!

Great job finishing this episode

Up Next

Golang Language Fundamentals
Go's standard library