Экземпляр Singleton продолжает создавать новые экземпляры в Go

#go #redis

#Вперед #redis

Вопрос:

Я использую redis для хранения сеансов для моего простого веб-приложения Go. Для этого мне нужен только один сеанс для одновременного доступа к соединению redis. Я искал информацию о реализации одноэлементных объектов в Go и следовал. Это код, который я сейчас внедряю:

Подключение Redis:

 package Datab

import (
    "github.com/gomodule/redigo/redis"
)

type cache struct {
    Conn redis.Conn
}

var singleCache *cache = nil

func GetSessionCache() *cache {

    if singleCache == nil {

        singleCache := amp;cache{}
        singleCache.Conn, _ = redis.DialURL("redis://localhost")
        // ^ SINGLECACHE IS NOT NIL HERE.

    }
    return singleCache
    // ^ SAYS THIS IS NIL!

}
  

Реализация Redis:

 package Handler

import (
    Datab "videodoox/DB" // this file contains the redis connection implementation
)

connStru := *Datab.GetSessionCache()
cache := connStru.Conn

connStru2 := *Datab.GetSessionCache()
cache2: = connStru.Conn
// ^ THIS CONNECTION HERE IS A COMPLETELY NEW INSTANCE.
  

Каждый раз, когда я получаю соединение, файл подключения redis создает новый экземпляр соединения.
Как мне создать новое соединение один раз и просто возвращать это соединение каждый раз?
Спасибо!

Комментарии:

1. singleCache := amp;cache{} => Это короткое объявление переменной, которое создает новую локальную переменную, затеняющую глобальную. Используйте назначение: singleCache = amp;cache{} . Также это небезопасно для одновременного использования. Лучше всего было бы выполнить инициализацию singleCache в функции package init() (или использовать once.Do() , если вам нужна отложенная инициализация).

2. @icza О, черт, я такой тупой! Это сработало как по волшебству! Большое спасибо. Да, я планирую использовать mutex для блокировки моих потоков и обеспечения потокобезопасности.

3. Обратите внимание на документацию Redigo по параллелизму . Вам нужно будет использовать мьютекс для управления доступом к методам подключения или изменить cache поле на пул.

4. попробуйте использовать это marcio.io/2015/07/singleton-pattern-in-go

Ответ №1:

Комментарии к первоначальному вопросу решают проблему, но просто для обеспечения полного решения ваш код может выглядеть следующим образом:

 package Datab

import (
    "sync"

    "github.com/gomodule/redigo/redis"
)

type cache struct {
    Conn redis.Conn
}

var singleCache *cache
var initOnce sync.Once

func GetSessionCache() *cache {
    initOnce.Do(func() {
        singleCache := amp;cache{}
        singleCache.Conn, _ = redis.DialURL("redis://localhost")
    })

    return singleCache
}
  

Всего пара дополнительных замечаний:

  • Нет необходимости указывать nil в качестве начального значения указателей нулевое значение для них nil по умолчанию ( var singleCache *cache vs var singleCache *cache = nil ).
  • Вы должны обработать потенциальную ошибку, возвращаемую redis.DialURL , а не просто пропустить ее с помощью _ .