Shoulder.dev Logo Shoulder.dev

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.

Explanation