предисловие
использовал некоторое время назадPython
Когда бизнес реализуется, яма находится, а точнее, дляPython
Яма, на которую непрофессионалу легко ступить;
Примерный код выглядит следующим образом:
class Mom(object):
name = ''
sons = []
if __name__ == '__main__':
m1 = Mom()
m1.name = 'm1'
m1.sons.append(['s1', 's2'])
print '{} sons={}'.format(m1.name, m1.sons)
m2 = Mom()
m2.name = 'm2'
m2.sons.append(['s3', 's4'])
print '{} sons={}'.format(m2.name, m2.sons)
Сначала определитеMom
класс, содержащий строку типаname
с типом спискаsons
Атрибуты;
Экземпляр класса сначала создается при использованииm1
и идиsons
Записывает список данных, затем создает экземплярm2
, также кsons
Записываются данные другого списка.
еслиJavaer
редко пишешьPython
Первый вывод, который приходит на ум, когда вы видите подобный код, должен быть таким:
m1 sons=[['s1', 's2']]
m2 sons=[['s3', 's4']]
Но на самом деле окончательный вывод:
m1 sons=[['s1', 's2']]
m2 sons=[['s1', 's2'], ['s3', 's4']]
Если вы хотите добиться желаемого значения, вам нужно немного изменить его:
class Mom(object):
name = ''
def __init__(self):
self.sons = []
Просто нужно изменить определение класса, и я считаю, что даже безPython
Вы должны быть в состоянии угадать причину, сравнив эти два кода с соответствующим опытом:
существуетPython
Если вам нужно использовать переменные в качестве переменных экземпляра (то есть каждый ожидаемый вывод), вам нужно определить переменные в конструкторе черезself
доступ.
если размещать только в классе, иJava
серединаstatic
Статические переменные имеют аналогичный эффект, эти данные являются общими для классов, что объясняет, почему происходит первый случай, так как один изsons
КMom
Классы общие, поэтому они будут накапливаться каждый раз.
Синглтон Python
теперь, когдаPython
Эффект от совместного использования переменных в одном классе может быть достигнут с помощью переменных класса.Возможна ли реализация шаблона singleton?
годный к употреблениюPython
изmetaclass
Эта функция динамически управляет созданием классов.
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
Сначала создайтеSingleton
Базовый класс , который мы затем используем какmetaclass
class MySQLDriver:
__metaclass__ = Singleton
def __init__(self):
print 'MySQLDriver init.....'
такSingleton
может контролироватьMySQLDriver
Этот класс создан; фактически, вSingleton
середина__call__
Процесс создания этого синглтона можно легко понять:
- Определить свойство частного класса
_instances
словарь (т.Java
серединаmap
) может быть общим для всего класса, независимо от того, сколько экземпляров создано. - Когда наш пользовательский класс использует
__metaclass__ = Singleton
После этого вы можете управлять созданием пользовательских классов, если экземпляр был создан, непосредственно из_instances
Выньте объект и верните, в противном случае создайте экземпляр и запишите его обратно_instances
, немногоSpring
Ощущение контейнера.
if __name__ == '__main__':
m1 = MySQLDriver()
m2 = MySQLDriver()
m3 = MySQLDriver()
m4 = MySQLDriver()
print m1
print m2
print m3
print m4
MySQLDriver init.....
<__main__.MySQLDriver object at 0x10d848790>
<__main__.MySQLDriver object at 0x10d848790>
<__main__.MySQLDriver object at 0x10d848790>
<__main__.MySQLDriver object at 0x10d848790>
Наконец, мы можем видеть, что синглтон успешно создан благодаря экспериментальным результатам.
Перейти синглтон
Поскольку некоторые предприятия в команде недавно начали использоватьgo
, так что я тоже хочу увидетьgo
Как реализовать синглтон в .
type MySQLDriver struct {
username string
}
В такой простой структуре (которую можно просто понимать какJava
серединаclass
) не похож наPython
а такжеJava
Также возможно объявить общие переменные класса;go
не существует в языкеstatic
Концепция чего-либо.
Но мы можем объявить глобальную переменную в пакете для достижения того же эффекта:
import "fmt"
type MySQLDriver struct {
username string
}
var mySQLDriver *MySQLDriver
func GetDriver() *MySQLDriver {
if mySQLDriver == nil {
mySQLDriver = &MySQLDriver{}
}
return mySQLDriver
}
При использовании этого:
func main() {
driver := GetDriver()
driver.username = "cj"
fmt.Println(driver.username)
driver2 := GetDriver()
fmt.Println(driver2.username)
}
не нужно строить напрямуюMySQLDriver
, но черезGetDriver()
функция получения черезdebug
также можно увидетьdriver
а такжеdriver1
Ссылка на тот же адрес памяти.
В реализации такой рутинной ситуации нет проблем, а остроумные друзья обязательно придумают иJava
Опять же, когда-то одновременный доступ не так прост.
существуетgo
, если их несколькоgoroutine
Одновременный доступGetDriver()
, то велика вероятность того, что несколькоMySQLDriver
пример.
Здесь все не так просто, это на самом деле относительноJava
Говоря о,go
простоapi
Доступ к критически важным ресурсам может быть обеспечен.
var lock sync.Mutex
func GetDriver() *MySQLDriver {
lock.Lock()
defer lock.Unlock()
if mySQLDriver == nil {
fmt.Println("create instance......")
mySQLDriver = &MySQLDriver{}
}
return mySQLDriver
}
func main() {
for i := 0; i < 100; i++ {
go GetDriver()
}
time.Sleep(2000 * time.Millisecond)
}
Немного изменил приведенный выше код и добавил
lock.Lock()
defer lock.Unlock()
Код может просто контролировать доступ к критическим ресурсам, даже если мы разрешим одновременное выполнение 100 сопрограмм,mySQLDriver
Экземпляры также инициализируются только один раз.
- здесь
defer
похожий наJava
серединаfinally
, добавить перед вызовом методаgo
ключевое слово для запуска сопрограммы.
Хотя он может удовлетворить требованиям параллелизма, на самом деле такая реализация недостаточно элегантна, подумайте об этом хорошенько.
mySQLDriver = &MySQLDriver{}
Создание экземпляра вызывается только один раз, но каждый последующий вызов должен быть заблокирован, что приводит к ненужным накладным расходам.
Такие сценарии одинаковы для каждого языка, возьмемJava
Например, вы часто видите такую реализацию синглтона:
public class Singleton {
private Singleton() {}
private volatile static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class){
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Это типичный синглтон с двойной проверкой, где выполняются две проверки, чтобы избежать последующего доступа к блокировке другими потоками.
то же самое дляgo
Похожий на:
func GetDriver() *MySQLDriver {
if mySQLDriver == nil {
lock.Lock()
defer lock.Unlock()
if mySQLDriver == nil {
fmt.Println("create instance......")
mySQLDriver = &MySQLDriver{}
}
}
return mySQLDriver
}
а такжеJava
Таким же образом, вынесение дополнительного суждения на исходной основе может привести к тому же результату.
Но не кажется ли вам, что такой код очень громоздкий, этотgo
который предоставилapi
Это очень просто:
var once sync.Once
func GetDriver() *MySQLDriver {
once.Do(func() {
if mySQLDriver == nil {
fmt.Println("create instance......")
mySQLDriver = &MySQLDriver{}
}
})
return mySQLDriver
}
По сути, нам просто нужно, независимо от ситуацииMySQLDriver
Экземпляр инициализируется только один раз для достижения цели синглтона, поэтому используйтеonce.Do()
Это позволяет выполнить код только один раз.
Глядя на исходный код, вы найдетеonce.Do()
Это также реализовано через блокировки, но базовая атомарная операция используется для выполнения проверки перед блокировкой, чтобы избежать блокировки каждый раз, и производительность будет лучше.
Суммировать
Я считаю, что в повседневной разработке вы редко столкнетесь с необходимостью реализовать синглтон самостоятельно, во-первых, в большинстве случаев синглтон нам не нужен, а даже если и требуется, то фреймворк обычно интегрирован.
похожий наgo
Таким образом, меньше фреймворков, и нам не нужно слишком много думать о параллелизме, когда нам нужно реализовать его самим; почувствуйте положение в верхней левой части нашего живота и подумайте об этом, этот объект, написанный нами, действительно имеет сотни или тысячи одновременных творений одновременно.
Однако это сравнение показывает, чтоgo
Синтаксис действительно лучше, чемJava
Это слишком лаконично, и в то же время легковесные сопрограммы и простая в использовании поддержка инструментов параллелизма кажутся лучше, чемJava
Гораздо элегантнее; последующие возможности пойти глубже.
Ссылка на ссылку: