← Назад к вопросам

Singleton паттерн в Go

1.0 Junior🔥 161 комментариев
#Основы Go

Условие

Реализуйте потокобезопасный Singleton паттерн в Go.

Интерфейс

type Database struct {
    connection string
}

func GetInstance() *Database

Требования

  • Гарантировать создание только одного экземпляра
  • Потокобезопасность при конкурентном доступе
  • Ленивая инициализация (создание при первом вызове)

Вопросы

  1. Покажите решение с sync.Once
  2. Покажите решение с sync.Mutex
  3. В чем преимущества sync.Once?

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

Singleton паттерн — создание только одного экземпляра объекта с потокобезопасным доступом.

Решение 1: sync.Once (РЕКОМЕНДУЕТСЯ)

var (
    instance *Database
    once     sync.Once
)

func GetInstance() *Database {
    once.Do(func() {
        instance = &Database{
            connection: "default-connection",
        }
    })
    return instance
}

Преимущества sync.Once:

  • Выполняет функцию ровно один раз при конкурентном доступе
  • Минимальный overhead (проверка без lock после первого вызова)
  • Стандартное решение в Go сообществе
  • Самое простое и надёжное

Решение 2: sync.Mutex (явное управление)

type databaseHolder struct {
    mu       sync.Mutex
    instance *Database
}

var holder = &databaseHolder{}

func GetInstance() *Database {
    holder.mu.Lock()
    defer holder.mu.Unlock()
    
    if holder.instance == nil {
        holder.instance = &Database{
            connection: "default-connection",
        }
    }
    
    return holder.instance
}

Минусы Mutex:

  • Lock на каждый вызов (даже когда уже создан)
  • Медленнее, чем sync.Once
  • Может быть deadlock если не осторожны

Сравнение подходов

ПодходПотокобезопасностьЛенивая инициализацияПроизводительность
sync.OnceДаДаОтличная
sync.MutexДаДаХорошая
Double-checkedНенадёжноДаХорошая

Тестирование

func TestSingletonConcurrency(t *testing.T) {
    instances := make([]*Database, 100)
    done := make(chan bool, 100)
    
    for i := 0; i < 100; i++ {
        go func(idx int) {
            instances[idx] = GetInstance()
            done <- true
        }(i)
    }
    
    for i := 0; i < 100; i++ {
        <-done
    }
    
    for i := 1; i < 100; i++ {
        if instances[i] != instances[0] {
            t.Error("Should be same instance")
        }
    }
}

Вывод

Используй sync.Once — это идеальное решение для Singleton в Go.

Singleton паттерн в Go | PrepBro