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.
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")
}
WaitGroup is particularly useful when coordinating multiple concurrent operations.WaitGroup to wait for.printNumbers. The &wg passes a pointer to the WaitGroup so that printNumbers can call Done() on it.wg.Done() is called when printNumbers exits, signaling the goroutine is complete. Using defer guarantees that Done() executes even if the function exits early or panics.main function from exiting prematurely and allows the goroutine to complete its task.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.
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:
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")
}
go printNumbers() statement starts a new goroutine. The printNumbers function runs concurrently with the rest of the code in main().printNumbers goroutine is running and printing numbers from 1 to 5 with a second delay between each, the main goroutine continues executing the next lines of code.