Как блокировка мьютекса работает с синглтоном?

#go #locking #mutex

#Вперед #блокировка #мьютекс

Вопрос:

Я реализовал синглтон с помощью db connector. Это работает нормально, но я не могу понять, какая БЛОКИРОВКА (мьютекс.Выполняется функция Lock()).

Я пытался это понять, но, может быть, кто-нибудь здесь мог бы рассказать мне что-нибудь еще об этом.

Я понимаю это так -> После того, как я использую Lock(), весь мой код между блокировкой и разблокировкой может быть запущен только ОДНОЙ подпрограммой.если это правда, не является ли это узким местом? Разве это не сильно замедляет мое приложение? каждый горутин должен ждать, пока другой конец выполнит этот код.

 package singleton

import (
    "database/sql"
    "fmt"
    "sync"
)

var connector *sql.DB
var mutex = amp;sync.Mutex{}

func OpenConnection() *sql.DB {
    if connector == nil {
        mutex.Lock()
        defer mutex.Unlock()
        if connector == nil {
            fmt.Println("Creating Single Instance Now")
            var err error
            connector, err = sql.Open("mysql", "db_user:.db_password@/books")

            if err != nil {
                panic(err)
            }
        }
    }

    return connector
}
  
 package server

import (
    "connection/singleton"
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "strings"
)

var connector *sql.DB

func SelectQuery(query string) (*sql.Rows, error) {
    connector = singelton.OpenConnection()
    query = strings.ToLower(query)
    if !strings.Contains(query, "select") {
        panic("Can't use select query to run different query")
    }

    results, err := connector.Query(query)

    if err != nil {
        panic(err.Error()) // proper error handling instead of panic in your app
    }

    return results, err
}
  

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

1. 1. Ваша реализация нарушена; двойная блокировка не работает. Ваш код колоритный. 2. Мьютексы — обычное дело, просто прочитайте, как они работают. 3. Открытие соединения с базой данных выполняется один раз, а не для каждого запроса. 4. Да, это было бы ужасным узким местом, но вы все равно не должны так поступать.

2. хм, где вы видите двойную блокировку? у меня есть только один mu. Lock() я использовал эту статью для создания этого кода: progolang.com/how-to-implement-singleton-pattern-in-go

3.Извините, «двойная блокировка» была не лучшим термином (двойная проверка синглтона лучше): проверка на == nil, а затем блокировка, а затем повторная проверка на == nil — это совершенно неправильно, поскольку это колоритный, а колоритный код в Go всегда неправильный. Даже в статье, из которой вы взяли этот код, говорится следующее: «Технически это все еще неправильный способ сделать это». (Что в статье неправильно, так это то, что это не правильно в 99,99% случаев, это неправильно на 100%, поскольку ни один колоритный код никогда не бывает правильным).Если вам нужен синглтон, используйте синхронизацию.Один раз (как объясняется в статье).

4. Что вы имеете в виду, говоря «колоритный код» я изменил код, следуя вашим советам, и я получил это: pastebin.com/Gg54tHRc он работает нормально, и я использую только один объект db connector.

5. «разве это не узкое место?» да, это явная цель мьютекса — создать узкое место, чтобы избежать проблем с параллелизмом. Вы правы, что это также может вызвать проблемы с производительностью, но когда компромисс между производительностью и корректностью, корректность всегда будет важнее; чтобы повысить производительность, вам придется искать способы уменьшить блокировку без ущерба для корректности.

Ответ №1:

Я понимаю это так -> После того, как я использую Lock(), весь мой код между блокировкой и разблокировкой может быть запущен только ОДНОЙ подпрограммой. если это правда, не является ли это узким местом? Разве это не сильно замедляет мое приложение? каждый горутин должен ждать, пока другой конец выполнит этот код.

Причина, по которой мы используем мьютекс здесь, заключается в инициализации подключения к БД только один раз. Это произойдет только в начале. Как только вы получите соединение, openConnection всегда будет возвращать соединение без ввода блока мьютекса. Так что проблем с производительностью не будет.

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