Python与Golang中实现单例模式

Python中重写__new__方法实现

import threading

import configs


class Util(object):
    _lock = threading.Lock()

    def __init__(self, host, port):
        self.host = host
        self.port = port

    # 重写 __new__ 方法实现单例模式
    # new方法里面实际上是创建了一个self对象,单例模式就是让new方法中生产同一个对象!
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with cls._lock:
                cls._instance = object.__new__(cls)
        return cls._instance


if __name__ == '__main__':
    u1 = Util(configs.HOST, configs.PORT)
    u2 = Util(configs.HOST, configs.PORT)
    u3 = Util(configs.HOST, configs.PORT)

    print(id(u1), id(u2), id(u3))  # 140618541058200 140618541058200 140618541058200
    print(id(u1) == id(u2))  # True
    print(id(u2) == id(u3))  # True

Go中实现1 - 终极写法

package main

import (
    "fmt"
    "os"
    "strconv"
    "sync"
)

// 参考资料里面有源码的分析以及sync.Once结构体的done为什么要放到最前面!
// https://geektutu.com/post/hpg-sync-once.html

type Config struct {
    Server string
    Port   int64
}

var (
    once   sync.Once
    config *Config
)

func ReadConfig() *Config {
    // 类似于 单例模式的实现!
    once.Do(func() {
        var err error
        config = &Config{Server: os.Getenv("TT_SERVER_URL")}
        config.Port, err = strconv.ParseInt(os.Getenv("TT_PORT"), 10, 0)
        if err != nil {
            config.Port = 8080
        }
        fmt.Println("init config......")
    })

    return config
}

func main() {

    // 开并发去初始化config
    wait := sync.WaitGroup{}
    for i := 0; i < 10; i++ {
        wait.Add(1)
        go func() {
            defer wait.Done()
            _ = ReadConfig()
        }()
    }
    wait.Wait()

    // 最后只打印一个:init config......

}

Go中实现2 - once.Do方法中的函数写在外面

package main

import (
    "fmt"
    "sync"
)

// 参考资料里面有源码的分析以及sync.Once结构体的done为什么要放到最前面!
// https://geektutu.com/post/hpg-sync-once.html

type Config struct {
    Server string
    Port   int64
}

var (
    once   sync.Once
    config *Config
)

func initConfig() {
    // 这里模拟从文件或者环境变量中获取server与port
    config = &Config{Server: "127.0.0.1", Port: 9999}

    fmt.Println("init config......")
}

func ReadConfig(i int) *Config {
    fmt.Println("i>>> ", i)
    // 类似于 单例模式的实现!
    //initConfig()
    once.Do(initConfig)
    return config
}

func main() {

    // 开并发去初始化config
    wait := sync.WaitGroup{}
    for i := 0; i < 10; i++ {
        wait.Add(1)
        go func(i int) {
            defer wait.Done()
            _ = ReadConfig(i)
        }(i)
    }
    wait.Wait()

    // 最后只打印一个:init config......

}

~~~