Goroutines

Aditya PradhanAditya Pradhan
2 min read

Concurrency is the computer science term for breaking up a single process into independent components and specifying how these components safely share data

Introduction

Goroutines are lightweight processes managed by the Go runtime.When a program is started the Go runtime creates threads which are allocated to the goroutines to run the program.

Why Goroutines?

People might be confused between multi-threading as both feels very similar.

  • The Goroutines is faster compared to the operating system level threads.

  • The Goroutines have smaller stack sizes and can grow eventually therefore providing better memory management.

  • Goroutines are faster as it is an intra-process without the operating system level calls.

  • The Go Scheduler is built inside the Go Program thus, can pause the goroutines when required along with garbage collection. To learn more about Go Scheduler: https://www.youtube.com/watch?v=YHRO5WQGh0k

“Goroutines are part of making concurrency easy to use. The idea, which has been around for a while, is to multiplex independently executing functions—coroutines—onto a set of threads. When a coroutine blocks, such as by calling a blocking system call, the run-time automatically moves other coroutines on the same operating system thread to a different, runnable thread so they won't be blocked. The programmer sees none of this, which is the point. The result, which we call goroutines, can be very cheap: they have little overhead beyond the memory for the stack, which is just a few kilobytes.”

Source: https://stackoverflow.com/questions/73562498/go-goroutine-under-the-hood

Using Goroutines

package main

import (
    "errors"
    "fmt"
    "log"
    "time"
)


func main() {
    defer fmt.Println("Hello from the Goroutine")
    go yo() 
    go printNumbers()

    var err error

    //err = go func() (WRONG)

    go func() {    //(RIGHT)
        err = work()
    }()

    time.Sleep(2 * time.Second)
    if err != nil {
        log.Fatal(err)
    } else {
        fmt.Println("Works Fine")
    }

}

func yo() {
    time.Sleep(1 * time.Second)
    fmt.Println("Yo~~~")
}

func printNumbers() {
    for i := 0; i < 10; i++ {
        fmt.Println(time.Now())
        time.Sleep(100 * time.Millisecond)
    }
}
func work() error {
    time.Sleep(1 * time.Second)
    return errors.New("Oh no!")
}

Best Practices

  • Always use channels or other synchronization tools (like sync.WaitGroup) to coordinate goroutines properly instead of relying on time.Sleep.

  • Avoid sharing data between goroutines without proper synchronization—it can lead to race conditions.

  • Keep your goroutines short-lived if possible. Long-running goroutines can lead to memory leaks if not handled carefully.

Conclusion

Goroutines are one of the most powerful features of Go. They simplify concurrency, making it more accessible and less error-prone than traditional multithreading. With minimal overhead and an efficient scheduler, they are ideal for building scalable, concurrent applications.

0
Subscribe to my newsletter

Read articles from Aditya Pradhan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Aditya Pradhan
Aditya Pradhan

Passionate and curious software developer with experience in building impactful web applications and solving complex problems. Skilled in React, Node.js, TypeScript, and database systems, with a focus on creating efficient and scalable solutions. Worked on dynamic projects, including developing dashboards, student portals, and API-driven platforms.. A continuous learner and enthusiastic collaborator, always open to exploring innovative ideas and opportunities. Let’s connect and create something meaningful! 🚀