Goroutines in Go

Goroutines in Go

Goroutines are a fundamental feature in the Go programming language, providing a lightweight mechanism for concurrent execution. This blog explores what goroutines are, how they work, and how to use them effectively.

What is a Goroutine?

A goroutine is a lightweight thread of execution in Go. Goroutines run concurrently with other goroutines and are managed by the Go runtime, which handles the scheduling and execution.

A goroutine is created using the go keyword followed by a function call.

package main

import (
    "fmt"
    "time"
)

func printMessage(message string) {
    for i := 0; i < 5; i++ {
        fmt.Println(message, i)
        time.Sleep(time.Millisecond * 500)
    }
}

func main() {
    go printMessage("Hello from Goroutine")
    printMessage("Hello from Main")
}

Explanation:

  • The go printMessage(...) call starts a new goroutine.
  • The main function continues executing independently of the goroutine.

Concurrency and Parallelism

  • Concurrency: Multiple tasks making progress at the same time.
  • Parallelism: Multiple tasks running simultaneously, usually on multiple CPU cores.

Goroutines provide concurrency, and Go’s runtime can manage multiple goroutines even on a single CPU core.

Synchronization with sync.WaitGroup

To wait for goroutines to finish, Go provides the sync.WaitGroup.

package main

import (
    "fmt"
    "sync"
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Printf("Worker %d starting\n", id)
    fmt.Printf("Worker %d finished\n", id)
}

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }

    wg.Wait()
    fmt.Println("All workers finished")
}

Explanation:

  • sync.WaitGroup is used to wait for multiple goroutines to finish.
  • wg.Add(1) indicates a new goroutine is starting.
  • wg.Done() marks a goroutine as finished.
  • wg.Wait() blocks until all goroutines have completed.

Channels for Communication

Channels provide a way for goroutines to communicate with each other and synchronize their execution.

package main

import "fmt"

func calculateSquare(num int, result chan int) {
    result <- num * num
}

func main() {
    results := make(chan int)

    go calculateSquare(4, results)
    square := <-results

    fmt.Println("Square:", square)
}

Explanation:

  • A channel is created with make(chan int).
  • The channel results is used to send data from a goroutine.
  • The calculateSquare function sends data through the channel.
  • The main function receives the data using <- results.

Buffered Channels

Buffered channels allow sending multiple values without blocking immediately.

package main

import "fmt"

func main() {
    messages := make(chan string, 2)

    messages <- "Hello"
    messages <- "World"

    fmt.Println(<-messages)
    fmt.Println(<-messages)
}

Explanation:

  • A buffered channel with capacity 2 is created.
  • Two values are sent without blocking.
  • Values are retrieved using <-.

Closing Channels

Channels can be closed using close().

package main

import "fmt"

func main() {
    messages := make(chan string)

    go func() {
        messages <- "Hello"
        close(messages)
    }()

    for msg := range messages {
        fmt.Println(msg)
    }
}

Explanation:

  • close(messages) closes the channel.
  • The for loop iterates until the channel is closed.

Conclusion

Goroutines are a powerful tool for concurrent programming in Go. By combining them with channels and the sync package, you can write efficient and scalable concurrent applications. Mastering goroutines will help you fully leverage Go's concurrency model.

Recent blogs
Структурные паттерны в программировании

Структурные паттерны в программировании

Порождающие паттерны в программировании

Порождающие паттерны в программировании

Генераторы и итераторы в PHP

Генераторы и итераторы в PHP

Объектно-ориентированное программирование в PHP

Объектно-ориентированное программирование в PHP

Структуры данных в PHP

Структуры данных в PHP