Goroutines and Concurrency
Goroutines are Go’s mechanism for running functions concurrently. Concurrency means making progress on multiple tasks at once, though not necessarily in parallel, depending on the runtime environment and CPU architecture.
Basic Goroutine Usage
A function can be executed as a goroutine by prefixing the call with the go keyword. If the main function exits before the goroutine completes, the goroutine is terminated, which can prevent expected output.
Channels for Communication and Synchronization
Channels enable communication between goroutines and coordinate execution. Sending and receiving data through channels uses arrow syntax, and receiving from a channel blocks execution until data is available.
Blocking Behavior
When the main routine reads from a channel, it waits until a goroutine sends data. This blocking mechanism ensures synchronization and prevents premature program termination.
Worker Pattern with Multiple Goroutines
Multiple worker goroutines can be spawned in a loop to process data concurrently. Results are sent back through a shared channel and collected in the main routine, enabling coordinated parallel processing.
Practical Usage in Web Development
In many web applications, explicit use of goroutines is unnecessary because underlying packages, such as routers, handle concurrency internally. Goroutines become most beneficial when processing large datasets or computational workloads.
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 goes way of running multiple
functions at the same time while this is not technically correct currency or 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 call
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 say hello and it
simply just prints out a message hello from go routine and then down here in our main
function we can we can call or we can turn this function into a go routine by adding the go
keyword and say go say hello and beneath it let's just print out something like println
main function
done go 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 comes in so
above our go say hello 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 say hello function and finally
we're gonna write some data to this to this channel and right now we're just gonna write
an empty string finally we can down here say again
arrow and then ch which just means reading from the from the channel so what have you 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 we send data and then later on we receive data from that
channel and when receiving data from the channel we send data to the channel 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 amount of data that we can split into chunks so let me just show an
example here so create a new function called funk 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 just going to use the id
and we're going to just going to use the id
and we're going to just going to use the id
and we're going to just going to use the id
and we're going to just going to use the id
and we're going to just going to use the id
and we're going to just going to use the id
and we're going to just going to use the id
and we're going to just going to use the id
and we're going to just going to use the id
and we're going to just going to use the id
and we're going to just going to use the id
finished d there we go
finished d there we go
finished d there we go and then we write that result to the
and then we write that result to the
and then we write that result to the channel
channel
channel all right so
all right so
all right so before
before
before here we just had one
here we just had one
here we just had one one go routine but we can spin up as
one go routine but we can spin up as
one go routine but we can spin up as many as we like so
many as we like so
many as we like so instead of doing it directly like this we
instead of doing it directly like this we
instead of doing it directly like this we can use a loop and say
can use a loop and say
can use a loop and say if for i equals one
if for i equals one
if for i equals one run the loop and then down here we
run the loop and then down here we
run the loop and then down here we simply go
simply go
simply go run worker as the index
run worker as the index
run worker as the index and then the channel
right then we can also collect the
right then we can also collect the
right then we can also collect the result from these three workers
result from these three workers
result from these three workers um where we're going to be saying for
um where we're going to be saying for
um where we're going to be saying for i equals
i equals
i equals one again i less than three
one again i less than three
one again i less than three i plus plus we increase it and
i plus plus we increase it and
i plus plus we increase it and then we just grab the result from this
then we just grab the result from this
then we just grab the result from this channel using this arrow notation and
channel using this arrow notation and
channel using this arrow notation and then we can print it
then we can print it
then we can print it out
out
out result
result
result there we go so here we spin up
there we go so here we spin up
there we go so here we spin up multiple workers
multiple workers
multiple workers we print out the result we would in a real
we print out the result we would in a real
we print out the result we would in a real scenario do something with the data
scenario do something with the data
scenario do something with the data right before we return it but this is a
right before we return it but this is a
right before we return it but this is a very simple illustration of how you can
very simple illustration of how you can
very simple illustration of how you can spin up multiple workers and then
spin up multiple workers and then
spin up multiple workers and then sync them and then do something with
sync them and then do something with
sync them and then do something with the result as it comes in
the result as it comes in
the result as it comes in for most tasks that you're going to be
for most tasks that you're going to be
for most tasks that you're going to be doing in web development you wouldn't
doing in web development you wouldn't
doing in web development you wouldn't need to reach for go routines
need to reach for go routines
need to reach for go routines some of the packages that we will be
some of the packages that we will be
some of the packages that we will be using already has go routines under the
using already has go routines under the
using already has go routines under the hood for example our router will use
hood for example our router will use
hood for example our router will use them to concurrently handle incoming
them to concurrently handle incoming
them to concurrently handle incoming requests
requests
requests but
but
but generally you need a large amount of
generally you need a large amount of
generally you need a large amount of data before go routines really become