РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
847 of 1593 menu

Тип sync.Once

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

Синтаксис

var once sync.Once once.Do(func())

Метод Do принимает функцию без параметров в качестве аргумента и выполняет ее только в первый раз. Последующие вызовы Do не выполняют функцию и возвращают управление немедленно.

Пример

Давайте рассмотрим базовый пример использования sync.Once для однократного выполнения функции инициализации:

package main import ( "fmt" "sync" ) func main() { var once sync.Once once.Do(func() { fmt.Println("Initialization performed") }) once.Do(func() { fmt.Println("This will not be printed") }) }

Результат выполнения кода:

"Initialization performed"

Пример

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

package main import ( "fmt" "sync" ) func main() { var once sync.Once var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func(id int) { defer wg.Done() once.Do(func() { fmt.Printf("Worker %d: initialization done\n", id) }) }(i) } wg.Wait() }

Результат выполнения кода (может отличаться порядком вывода):

"Worker 3: initialization done"

Пример

Типичный сценарий использования sync.Once - инициализация синглтона. В этом примере мы создаем структуру, которая инициализируется только при первом обращении:

package main import ( "fmt" "sync" ) type Config struct { Settings map[string]string } var ( config *Config once sync.Once ) func GetConfig() *Config { once.Do(func() { fmt.Println("Initializing config") config = &Config{ Settings: map[string]string{ "key": "value", }, } }) return config } func main() { var wg sync.WaitGroup for i := 0; i < 3; i++ { wg.Add(1) go func() { defer wg.Done() cfg := GetConfig() fmt.Println(cfg.Settings["key"]) }() } wg.Wait() }

Результат выполнения кода:

"Initializing config" "value" "value" "value"

Пример

Важно помнить, что если функция, переданная в Do, запаникует, то sync.Once считается выполненным, и последующие вызовы Do не повторят ее выполнение. Рассмотрим этот случай:

package main import ( "fmt" "sync" ) func main() { var once sync.Once once.Do(func() { fmt.Println("First call") panic("something went wrong") }) once.Do(func() { fmt.Println("This will not be printed") }) fmt.Println("Program continues") }

Результат выполнения кода:

"First call" "panic: something went wrong"

Смотрите также

  • тип sync.Mutex,
    который используется для взаимного исключения при работе с общими ресурсами
  • тип sync.WaitGroup,
    который ожидает завершения группы горутин
  • тип sync.RWMutex,
    который предоставляет блокировку для чтения и записи
  • тип sync.Map,
    который представляет конкурентно-безопасную карту
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить