W Go globalne zmienne są inicjalizowane w porządku deklaracji plików i sekwencji ich funkcji init. Od tego zależy poprawność dostępu do globalnego stanu: jeśli zmienna w jednym pakiecie zależy od wartości zmiennej innego pakietu, ale ten pakiet nie został jeszcze zainicjalizowany — wystąpi błąd lub nieoczekiwane zachowanie.
Nie można bezpośrednio ustalić "kolejności startowej" między funkcjami init różnych pakietów. Kompilator określa tę kolejność na podstawie grafu importu.
main.main().Przykład bezpiecznej, opóźnionej inicjalizacji (lazy init):
var cfg *Config var once sync.Once func GetConfig() *Config { once.Do(func() { cfg = LoadConfigFromDisk() }) return cfg }
Pytanie: Czy funkcje init różnych pakietów mogą działać równocześnie (równolegle) podczas uruchamiania programu w Go?
Poprawna odpowiedź: Nie, funkcje init i globalne zmienne są wykonywane ściśle sekwencyjnie w kolejności określonej przez kompilator podczas analizy zależności między pakietami. Nie ma równoległego uruchamiania funkcji init.
Historia
W dużym projekcie kilka modułów ładowało globalne konfiguracje z dysku przez init(). Jeden moduł zależał od drugiego, ale z powodu przebudowy grafu go.mod, kolejność inicjalizacji się zmieniła — w rezultacie wartości konfiguracji okazały się puste! Błąd objawiał się losowo, w zależności od kolejności kompilacji, i został znaleziony dopiero po przeanalizowaniu zależności i przeniesieniu inicjalizacji do jawnej funkcji.
Historia
W serwisie REST do buforowania słowników używano globalnej mapy bez mutexa. Inicjalizacja rozpoczynała się z kilku goroutine, które startowały w init. W efekcie — data race, okresowe paniki, nieprawidłowe dane wewnątrz mapy. Po zamianie na sync.Once i jawnym wywołaniu inicjalizacji problem zniknął.
Historia
Globalny logger był tworzony w funkcji init jednego z pomocniczych pakietów, jednak inny pakiet odwoływał się do tego loggera również przy starcie, przed jego inicjalizacją. W efekcie część logów o starcie ginęła, dopóki logger jeszcze nie istniał. Rozwiązanie — wstrzykiwanie zależności i jawna inicjalizacja loggera przed uruchomieniem wszystkich serwisów.