Go'da global değişkenler dosyaların bildirim sırasına ve ilgili init fonksiyonlarının sırasına göre başlatılır. Bu, global duruma doğru bir şekilde erişimi etkiler: bir paketteki bir değişken başka bir paketin değişkeninin değerine bağlıysa, ancak bu paket henüz başlatılmamışsa — bir hata veya belirsiz davranış oluşur.
Farklı paketlerin init fonksiyonları arasında "başlangıç sırası" doğrudan tanımlanamaz. Derleyici, bu sırayı ithalat grafiğine göre belirler.
main.main() fonksiyonunun çağrılmasından önce başlatılır.Güvenli, gecikmeli başlatma örneği (lazy init):
var cfg *Config var once sync.Once func GetConfig() *Config { once.Do(func() { cfg = LoadConfigFromDisk() }) return cfg }
Soru: Farklı paketlerin init fonksiyonları Go programı çalıştırıldığında aynı anda (paralel) çalışabilir mi?
Doğru cevap: Hayır, init fonksiyonları ve global değişkenler, paketler arasındaki bağımlılıkların analizi sırasında derleyici tarafından belirlenen sırayla sıkı bir şekilde sırayla çalışır. Init fonksiyonlarının paralel çalışması gerçekleşmez.
Hikaye
Büyük bir projede birkaç modül, global konfigürasyonları diskten init() aracılığıyla yükleyordu. Bir modül diğerine bağımlıydı, ancak go.mod grafiğinin yeniden düzenlenmesi nedeniyle başlatma sırası değişti — ve aniden konfigürasyon değerleri boş çıktı! Hata, derleme sırasına bağlı olarak rastgele bir şekilde belirdi ve yalnızca bağımlılıkların analizi ve başlatmayı açık bir fonksiyona taşıdıktan sonra bulundu.
Hikaye
REST servisinde rehberlerin önbelleklemesi için mutex olmadan global bir map kullanılıyordu. Başlatma, init'te başlatılan birkaç goroutine'den başlamıştı. Sonuç olarak — data race, dönemsel panik, map içinde geçersiz veriler. sync.Once ile değiştirilip başlatma açıkça çağrıldığında sorun ortadan kalktı.
Hikaye
Global logger, yardımcı paketlerden birinin init fonksiyonunda yaratılıyordu. Ancak başka bir paket, bu logger'a başlatma sırasında, henüz başlatılmadan erişiyordu. Sonuç olarak, başlatma ile ilgili logların bir kısmı kayboluyordu, çünkü logger henüz mevcut değildi. Çözüm — bağımlılık enjekte edilmesi ve logger'ın tüm servisler çalışmadan önce açık bir şekilde başlatılmasıdır.