En Go, les variables globales sont initialisées dans l'ordre de déclaration des fichiers et de la séquence de leurs fonctions init. Cela dépend de la correction de l'accès à l'état global : si une variable dans un paquet dépend de la valeur d'une variable d'un autre paquet, mais que ce paquet n'a pas encore été initialisé, cela provoquera une erreur ou un comportement non évident.
Il n'est pas possible de définir directement un "ordre de démarrage" entre les fonctions init de différents paquets. Le compilateur détermine cet ordre en fonction du graphique d'importation.
main.main().Exemple d'initialisation différée sécurisée (lazy init):
var cfg *Config var once sync.Once func GetConfig() *Config { once.Do(func() { cfg = LoadConfigFromDisk() }) return cfg }
Question : Les fonctions init de différents paquets peuvent-elles s'exécuter simultanément (parallèlement) lors du démarrage d'un programme en Go ?
Réponse correcte : Non, les fonctions init et les variables globales s'exécutent strictement de manière séquentielle dans l'ordre défini par le compilateur lors de l'analyse des dépendances entre les paquets. Il n'y a pas d'exécution parallèle des fonctions init.
Histoire
Dans un grand projet, plusieurs modules chargeaient des configurations globales à partir du disque via init(). Un module dépendait d'un autre, mais en raison de la restructuration du graphique go.mod, l'ordre d'initialisation a changé - et soudain, les valeurs de configuration sont devenues vides ! L'erreur apparaissait de manière aléatoire, dépendant de l'ordre de construction, et n'a été trouvée qu'après l'analyse des dépendances et le transfert de l'initialisation dans une fonction explicite.
Histoire
Dans un service REST, un map global était utilisé pour la mise en cache de répertoires sans mutex. L'initialisation était lancée par plusieurs goroutines démarrant dans init. En conséquence - data race, paniques périodiques, données non valides dans le map. Après remplacement par sync.Once et appel explicite de l'initialisation, le problème a disparu.
Histoire
Un logger global était créé dans la fonction init d'un des paquets auxiliaires, mais un autre paquet accédait également à ce logger au démarrage, avant son initialisation. En fin de compte, une partie des journaux de démarrage était perdue tant que le logger n'existait pas encore. La solution - injection de dépendances et initialisation explicite du logger avant le démarrage de tous les services.