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
init
functions—happens in a single goroutine, sequentially, one package at a time. Aninit
function may launch other goroutines, which can run concurrently with the initialization code. However, initialization always sequences theinit
functions: 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)