Concurrency in Go: Goroutines and Channels
Chigozie Nwokoye
Experienced Back-End Engineer | Golang | Python | Typescript | Devops
The Go programming language was designed with concurrency in mind, making it easy for developers to write concurrent programs.? In Go, concurrency is achieved through goroutines and channels. In this article, we'll explore the basics of these concepts with simple examples.
Goroutines:
A goroutine is a lightweight thread of execution managed by the Go runtime. It is a function that runs concurrently or in parallel with the other goroutines in the same address space.
To create a goroutine, you use the go keyword followed by a function invocation:
package main
import "fmt"
func routineFunction() {}
func main() {
fmt.Println("Goroutines")
go func() {
// Your concurrent code here
}()
go routineFunction()
}
In the code above, we have 2 go routines, one calling an anonymous function, and the other calling the function routineFunction. This is not likely in this example, but the second function call starts running in the background whether the first is done or not, in other words, they are both running concurrently.?
Another example of goroutines in action:
package main
import (
"fmt"
"time"
)
func sayHello() {
for i := 0; i < 3; i++ {
fmt.Println("Hello!")
time.Sleep(time.Millisecond * 200)
}
}
func main() {
go sayHello() // Start a new goroutine
time.Sleep(time.Second) // Sleep to allow goroutine complete
fmt.Println("Main function")
}
In this example, sayHello is a function that prints "Hello!" three times with a short delay. By calling go sayHello(), we create a new goroutine that runs concurrently with the main function. The time.Sleep is used to ensure that the main function doesn't exit before the goroutine completes.
Channels:
Channels are a way for goroutines to communicate with each other and synchronize their execution. They provide a safe and efficient means of passing data between goroutines.
We create a channel that takes values of a certain type like this:
ch := make(chan Type)
or
ch := make(chan Type, capacity)
These are 2 ways you can make a channel, the first doesn’t require you to provide the capacity of the channel.?
Actual examples of creating? a channel that allows string values:
领英推荐
ch := make(chan string)
or
ch := make(chan string, 8)
Now that we know how to create a channel, we need to know how to add and receive data through the channel.?
This is an example of passing data into a channel:
ch := make(chan string)
name := “Chigozie”
ch <- name
Here, the name is getting sent into the channel, and this name can be received from the channel like this.
name, ok := <-ch
// Check if the channel is closed and empty
if !ok {
}
Examples:
I will use 2 fairly complex examples to put all we’ve learned so far together, let’s try to slowly assimilate what is going on in these examples.
package main
import "fmt"
func main() {
// Create a channel of integers
dataChannel := make(chan int)
// Start a goroutine to send data into the channel
go func() {
for i := 1; i <= 5; i++ {
dataChannel <- i // Sending data into the channel
}
close(dataChannel) // Close the channel when done sending data
}()
// Receiving data from the channel
for {
// Receive data from the channel
// The receive operator `<-` is used with the channel variable
// If the channel is closed and empty, ok will be false
data, ok := <-dataChannel
// Check if the channel is closed and empty
if !ok {
break // Exit the loop if the channel is closed
}
// Process the received data (in this case, just print it)
fmt.Println("Received:", data)
}
}
In this example, we created a channel dataChannel that takes integer values. We then started a go routine that loops from 1 to 5 and passes the integer value into the channel, and this go routine closes the channel when it is done. Next, we have an infinite for loop that waits for data to enter into the channel, receives the data, and prints it out. It also checks if the channel is closed, it will stop the loop when the go routine closes the channel.
Next example we will use the sync package to modify the process a bit:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
// Create a channel to pass data between goroutines
dataChannel := make(chan int)
// Use a WaitGroup to wait for the goroutine to finish
var wg sync.WaitGroup
wg.Add(1)
// Start the goroutine to send data into the channel
go func() {
defer wg.Done()
// Send some data into the channel
for i := 1; i <= 5; i++ {
dataChannel <- i
time.Sleep(time.Second) // Simulating some processing time
}
// Close the channel to signal that no more data will be sent
close(dataChannel)
}()
// Receive data outside the goroutine
go func() {
// Wait for the goroutine to finish
wg.Wait()
// Range over the channel to receive data until it's closed
for data := range dataChannel {
// Process the received data (in this case, just print it)
fmt.Println("Received:", data)
}
fmt.Println("Channel closed. No more data.")
}()
// Wait for the receiving goroutine to finish (it will finish when the channel is closed)
// In a real-world scenario, you might want to use a more sophisticated way to wait for goroutines to finish.
select {}
}
Here, we have 2 go routines, the first routine loops from 1 to 5 and passes the number into the channel. Another thing to note is that we initiated a wait group from the sync package. We are doing wg.Add(1) to tell the wait group that we want to wait for 1 goroutine to complete. Now inside the goroutine, we defer wg.Done() so that we inform the wait group at the end of the function that we have completed the one goroutine we informed it about earlier. Concurrently the second goroutine is waiting for the waitgroup to tell it that the goroutines are complete. After which it starts looping through the channel and receiving data from it. This data is then printed to the console.
Conclusion:
Concurrency in Go is made simple with goroutines and channels. Goroutines enable concurrent execution, and channels facilitate communication between them. By leveraging these features, developers can write efficient and scalable concurrent programs straightforwardly.
This is just the tip of the iceberg when it comes to Go concurrency. As you delve deeper into the language, you'll discover more advanced features and techniques to handle concurrency robustly and elegantly. Happy coding!
--
8 个月Good day bro please can we chat on WhatsApp please there is something I want to ask you Thank you my WhatsApp number is 09157365579