Один раз: sync.Once

К задачам
Средняя
Concurrency

Условие задачи

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

package main

import (
    "fmt"
    "sync"
)

var once sync.Once

func initResource() {
    fmt.Println("Ресурс инициализирован")
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            // TODO: initResource должен вызваться только один раз
        }()
    }

    wg.Wait()
}
package main

import (
    "fmt"
    "sync"
)

var once sync.Once

func initResource() {
    fmt.Println("Ресурс инициализирован")
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            // TODO: initResource должен вызваться только один раз
        }()
    }

    wg.Wait()
}

Подсказка

- Используй once.Do(...) - Метод Do гарантирует, что переданная функция будет вызвана только один раз независимо от количества вызовов.

Решение

sync.Once — безопасный способ гарантировать однократное выполнение. Удобен для lazy-инициализации.

package main

import (
    "fmt"
    "sync"
)

var once sync.Once

func initResource() {
    fmt.Println("Ресурс инициализирован")
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            once.Do(initResource)
        }()
    }

    wg.Wait()
}
package main

import (
    "fmt"
    "sync"
)

var once sync.Once

func initResource() {
    fmt.Println("Ресурс инициализирован")
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            once.Do(initResource)
        }()
    }

    wg.Wait()
}