Asynchronous Operations — Start a Goroutine and Waiting

Starting a goroutine in Go for asynchronous operations is straightforward, but synchronizing and properly waiting for these goroutines to complete requires careful handling to ensure that your program doesn't exit prematurely or introduce race conditions. Below, I'll show an example of how to start a goroutine and correctly wait for it using a sync.WaitGroup, which is a common and recommended practice in Go.

Example: Starting a Goroutine and Properly Waiting

This example will demonstrate how to start a goroutine to perform an operation and use a sync.WaitGroup to wait for the goroutine to finish before the main function completes.

package main

import (
    "fmt"
    "sync"
    "time"
)

// printNumbers prints numbers from 1 to 5 with a delay
func printNumbers(wg *sync.WaitGroup) {
    defer wg.Done() // Signal that this goroutine is done at the end of the function
    for i := 1; i <= 5; i++ {
        fmt.Println("Number:", i)
        time.Sleep(1 * time.Second) // Sleep for 1 second to simulate work
    }
}

func main() {
    var wg sync.WaitGroup

    fmt.Println("Main execution starts")

    // Add one goroutine to the WaitGroup
    wg.Add(1)

    // Start the goroutine
    go printNumbers(&wg)

    fmt.Println("Main execution continues")

    // Wait for all goroutines in the WaitGroup to complete
    wg.Wait()

    fmt.Println("Main execution ends")
}

Explanation:

This method is the standard approach to managing asynchronous operations in Go when you need to ensure that all work is completed before the program exits. This technique avoids the use of arbitrary sleep statements and provides a more controlled and reliable way to handle concurrency.

Asynchronous Operations — Start a Goroutine

In Go, a goroutine is a lightweight thread managed by the Go runtime. Goroutines are used to perform concurrent operations, allowing you to run multiple tasks in parallel. Starting a goroutine is very simple and requires only the go keyword followed by a function call.

Here’s a basic example demonstrating how to start a goroutine to perform some background operations:

Example: Starting a Goroutine

package main

import (
    "fmt"
    "time"
)

// printNumbers prints numbers from 1 to 5 with a delay
func printNumbers() {
    for i := 1; i <= 5; i++ {
        fmt.Println(i)
        time.Sleep(1 * time.Second) // Sleep for 1 second between numbers
    }
}

func main() {
    fmt.Println("Main execution starts")

    // Start the goroutine
    go printNumbers()

    // Main goroutine does other work
    fmt.Println("Main execution continues")
    time.Sleep(500 * time.Millisecond) // Small delay to observe output
    fmt.Println("Main execution doing some work")

    // Wait for the goroutine to finish (not the recommended way to synchronize)
    time.Sleep(6 * time.Second) // Ensure main doesn't exit before printNumbers finishes
    fmt.Println("Main execution ends")
}

Key Points of the Example: