Зачем нужен sync.Once

Ответ

sync.Once гарантирует, что определенный код выполнится ровно один раз, даже если его вызывают из нескольких горутин. Это полезно для ленивой инициализации или однократного выполнения ресурсоемких операций.

Пример:

var (
    once sync.Once
    config map[string]string
)

func loadConfig() {
    once.Do(func() {
        // Этот код выполнится только один раз, независимо от количества вызовов loadConfig
        config = readConfigFromFile() 
    })
}

// Вспомогательная функция для примера
func readConfigFromFile() map[string]string {
    // Имитация чтения конфигурации
    return map[string]string{"key": "value"}
}

Ключевые особенности:

  • Потокобезопасность: Гарантирует корректное выполнение в конкурентной среде.
  • Однократное выполнение: Функция, переданная в Do, будет вызвана только один раз за всё время жизни программы.
  • Игнорирование последующих вызовов: После первого успешного выполнения Do, все последующие вызовы once.Do не будут выполнять переданную функцию, но будут ждать завершения первого выполнения, если оно еще не закончено.
  • Применение: Идеально подходит для инициализации синглтонов, загрузки конфигураций, установки соединений с базами данных или других операций, которые должны произойти ровно один раз.

sync.Once является фундаментальным примитивом для обеспечения корректной и эффективной инициализации в конкурентных Go-приложениях.