Материал проходит вычитку — возможны неточности.
Урок 92 из 118

sync.Once

Каждый запрос к S3 поднимал подключение и грузил креды заново. Миша перевёл инициализацию на один раз: первый запрос готовил клиента, остальные дожидались готового. Повторные запросы пошли заметно быстрее.

Главная мысль

sync.Once гарантирует, что функция выполнится ровно один раз, сколько бы горутин ни вызвали Do — и все дождутся её завершения.

Ленивая инициализация

var (
    once     sync.Once
    s3Client *S3Client
)

func GetS3Client() *S3Client {
    once.Do(func() {
        s3Client = newS3Client()
    })
    return s3Client
}

Do выполняет функцию один раз. Первый вызвавший запускает newS3Client, остальные, пришедшие во время выполнения, блокируются и после возврата Do видят готовый s3Client. Это каноническая ленивая инициализация — без проверок «а не инициализировали ли уже».

Паника «засчитывается»

once.Do(func() {
    panic("инициализация упала")
})
once.Do(func() {
    fmt.Println("не выполнится")
})

Если функция внутри Do паникует, Once считает вызов выполненным: повторный Do ничего не запустит. Для инициализации это значит: упала — навсегда. Если нужна возможность «попробовать ещё раз», Once не подходит.

Где Once уместен

Одноразовая инициализация: создание S3-клиента, пула соединений, регистрация обработчиков. Везде, где «сделать один раз» важнее, чем «сделать при старте». Отличие от init: Once — лениво, в момент первого обращения, а не при загрузке пакета.

В следующем уроке

Вы узнаете:

  • чем Once отличается от init() и проверки if nil под мьютексом
  • как happens-before работает через Once
Задание · вопросы

Проверьте себя

Вопрос 1 из 3

once.Do запускает функцию с panic. Что при втором вызове Do?

Вопрос 2 из 3

Чем Once лучше ручной двойной проверки под мьютексом?

Вопрос 3 из 3

После завершения once.Do все читатели видят инициализированную структуру целиком?

Итоги

Once — «ровно один раз» с ожиданием остальных. Паника засчитывается. Это ленивая инициализация для вещей, которые создаются дорого.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки