I’ve been on an unannounced, unplanned, month-long hiatus, what with moving my family across the globe. But with the new year starting, and the worst of the chaos behind me, I’m going to try to get back in the saddle again, and pick up where I left off.
And what better way to initialize 2025 than with talking about init?
Program initialization
…
Package initialization—variable initialization and the invocation of
initfunctions—happens in a single goroutine, sequentially, one package at a time. Aninitfunction may launch other goroutines, which can run concurrently with the initialization code. However, initialization always sequences theinitfunctions: it will not invoke the next one until the previous one has returned.
I think this is pretty clear, and intuitive. As the program initializes each package, any init functions in that package (and remember, there can be more than one per package, or even per file!), are run, one at a time, in a single goroutine.
If you don’t want your program initialization to wait for your init function to complete running, you have the option to launch a go routine from within such a function:
func init() {
fmt.Println("init 1")
go func() {
time.Sleep(time.Second)
fmt.Println("init 1b")
}()
}
func init() {
fmt.Println("init 2")
}
This will output:
init 1
init 2
init 1b
However, be advised that this is almost always a bad idea. First off, just in general, init functions should be used minimally, if at all.
Second, if your init function does something time consuming, and you throw it into a go routine, you need to make sure that there’s a lock of some sort, to ensure that something doesn’t try to use the uninitialized data before it’s ready. Certainly doable, but can be a hassle, hard to debug, and is often (almost always) a sign of a poor architecture. Look for alternatives.
Quotes from The Go Programming Language Specification Language version go1.23 (June 13, 2024)