Concurrency with Goroutines

Go’s concurrency model, built on goroutines and channels, allows for efficient handling of multiple tasks simultaneously. This enhances performance and responsiveness, especially in scenarios requiring I/O operations or complex computations.

What are Goroutines?

Goroutines are lightweight, concurrent execution units managed by the Go runtime. They are created using the go keyword, which launches a new goroutine to execute a function concurrently. [Source: https://go.dev/blog/concurrency-is-not-parallelism]

Example:

package main
          
          import (
              "fmt"
              "time"
          )
          
          func say(s string) {
              for i := 0; i < 5; i++ {
                  time.Sleep(100 * time.Millisecond)
                  fmt.Println(s)
              }
          }
          
          func main() {
              go say("world")
              say("hello")
          }
          

Why is Concurrency with Goroutines Important?

Concurrency empowers Go programs to:

  • Improve Responsiveness: Allowing tasks to run in parallel prevents blocking of the main thread, ensuring responsiveness to user interactions.
  • Maximize CPU Utilization: Goroutines effectively leverage multi-core processors, enabling parallel execution of tasks for enhanced performance.
  • Simplified Code Structure: Go’s concurrency features allow for clean and modular code, making it easier to manage complex systems.

Channels

Channels act as communication pathways between goroutines. They provide a safe and synchronized method for passing data between concurrently running functions.

Example:

package main
          
          import (
              "fmt"
          )
          
          func sum(s []int, c chan int) {
              sum := 0
              for _, v := range s {
                  sum += v
              }
              c <- sum // Send sum to channel c
          }
          
          func main() {
              a := []int{7, 2, 8, -9, 4, 0}
          
              c := make(chan int) // Create a channel
              go sum(a[:len(a)/2], c)
              go sum(a[len(a)/2:], c)
          
              x := <-c // Receive from c
              y := <-c // Receive from c
              fmt.Println(x, y, x+y)
          }
          

This example demonstrates how channels facilitate communication and synchronization between goroutines, allowing for efficient data processing.