What happens when main returns while other goroutines are still running? What does this print?
Question 166MediumGo 1.22 to 1.25
package main
import "fmt"
func main() {
go func() {
defer fmt.Println("deferred")
fmt.Println("in goroutine")
}()
fmt.Println("main done")
}
Most likely it prints only main done. When main.main returns, the runtime calls exit(0) right away. Other goroutines are not waited for, and their deferred calls do not run. Sometimes you will see in goroutine as well, but nothing guarantees it.
The fix is to wait explicitly with sync.WaitGroup, a done channel, or errgroup. Go 1.25 added wg.Go(f), which does Add and Done for you:
var wg sync.WaitGroup
wg.Go(func() { fmt.Println("in goroutine") })
wg.Wait()
Related: os.Exit also skips deferred calls, even in the current goroutine. runtime.Goexit() called in main ends main but lets the other goroutines keep running. If they all finish or block, you get "fatal error: no goroutines (main called runtime.Goexit) - deadlock!".
More on Goroutines & the Scheduler
- Q164How many goroutines can a Go program run? How do you bound them?
- Q165Why doesn't Go expose goroutine IDs, and how do you "kill" a goroutine?
- Q167What happens if a goroutine panics? Can the parent recover it?
- Q168What does this print? (Closure capture and the Go 1.22 loop variable change)
- Q169When does the Go runtime report "all goroutines are asleep - deadlock!" and when doesn't it?
- Q170Concurrency vs. parallelism in Go — can goroutines run in parallel with GOMAXPROCS=1?