Go 中的单例

发布于 2024-08-12 23:44:47 字数 24 浏览 6 评论 0原文

如何在Go语言中实现单例设计模式?

How does one implement the Singleton design pattern in the go programming language?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

青衫儰鉨ミ守葔 2024-08-19 23:44:47

抛开实现单例模式是否是个好主意的争论,这里有一个可能的实现:

package singleton

type single struct {
        O interface{};
}

var instantiated *single = nil

func New() *single {
        if instantiated == nil {
                instantiated = new(single);
        }
        return instantiated;
}

singleinstantiated 是私有的,但 New()< /code> 是公开的。因此,您无法在不通过 New() 的情况下直接实例化 single,并且它会使用私有布尔值 instantiated 来跟踪实例化的数量。根据喜好调整 single 的定义。

然而,正如其他几个人指出的,这不是线程安全的,除非您仅在 init() 中初始化您的单例。更好的方法是利用 sync.Once 来为您完成艰苦的工作:

package singleton

import "sync"

type single struct {
        O interface{};
}

var instantiated *single
var once sync.Once

func New() *single {
        once.Do(func() {
                instantiated = &single{}
        })
        return instantiated
}

另请参阅 hasan j 的建议,即仅将包视为单例。最后,请考虑其他人的建议:单例通常是有问题的实现的指标。

Setting aside the argument of whether or not implementing the singleton pattern is a good idea, here's a possible implementation:

package singleton

type single struct {
        O interface{};
}

var instantiated *single = nil

func New() *single {
        if instantiated == nil {
                instantiated = new(single);
        }
        return instantiated;
}

single and instantiated are private, but New() is public. Thus, you can't directly instantiate single without going through New(), and it tracks the number of instantiations with the private boolean instantiated. Adjust the definition of single to taste.

However, as several others have noted, this is not thread-safe, unless you're only initializing your singleton in init(). A better approach would be to leverage sync.Once to do the hard work for you:

package singleton

import "sync"

type single struct {
        O interface{};
}

var instantiated *single
var once sync.Once

func New() *single {
        once.Do(func() {
                instantiated = &single{}
        })
        return instantiated
}

See also, hasan j's suggestion of just thinking of a package as a singleton. And finally, do consider what others are suggesting: that singletons are often an indicator of a problematic implementation.

禾厶谷欠 2024-08-19 23:44:47

最好的方法是:

 package singleton

 import "sync"

 type singleton struct {
 }

 var instance *singleton
 var once sync.Once

 func GetInstance() *singleton {
     once.Do(func() {
         instance = &singleton{}
     })
     return instance
 }

您应该阅读此链接

The best approach will be:

 package singleton

 import "sync"

 type singleton struct {
 }

 var instance *singleton
 var once sync.Once

 func GetInstance() *singleton {
     once.Do(func() {
         instance = &singleton{}
     })
     return instance
 }

You should read this Link

夏至、离别 2024-08-19 23:44:47

只需将变量和函数放在包级别即可。

另请参阅类似的问题:How to make a singleton in Python

Just put your variables and functions at the package level.

Also see similar question: How to make a singleton in Python

山人契 2024-08-19 23:44:47

我认为在并发世界中,我们需要更加意识到这些行不是自动执行的:

if instantiated == nil {
    instantiated = new(single);
}

我会遵循@marketer的建议并使用包“sync”

import "sync"

type MySingleton struct {

}

var _init_ctx sync.Once 
var _instance *MySingleton

func New() * MySingleton {
     _init_ctx.Do( func () { _instance = new(MySingleton) }  )
     return _instance 
}

I think that in a concurrent world we need to be a bit more aware that these lines are not executed atomically:

if instantiated == nil {
    instantiated = new(single);
}

I would follow the suggestion of @marketer and use the package "sync"

import "sync"

type MySingleton struct {

}

var _init_ctx sync.Once 
var _instance *MySingleton

func New() * MySingleton {
     _init_ctx.Do( func () { _instance = new(MySingleton) }  )
     return _instance 
}
傻比既视感 2024-08-19 23:44:47

在尝试找到一种方法来屈服于你的意愿之前,你可能需要看看一些文章:

总之,随着时间的推移,人们发现单例并不是最佳的,恕我直言,尤其是如果您尝试进行任何测试驱动的开发:在许多层面上,它们几乎与全局变量一样糟糕。

[免责声明:我知道这不是对你的问题的严格回答,但它确实相关]

Before trying to find a way to bend Go to your will, you might want to take a look at some articles:

In summary, over time people have found singletons to be less than optimal, and imho especially if you are trying to do any test-driven development: on many levels they are pretty much as bad as global variables.

[disclaimer: I know its not a strict answer to your question but it really is relevant]

静若繁花 2024-08-19 23:44:47

正如您在以下代码中看到的那样,很简单:

package main

import (
    "fmt"
    "sync"
)

type singleton struct {
    count int
    sync.RWMutex
}

var instance singleton 

func GetInstance() *singleton {
    return &instance 
}

func (s *singleton) AddOne() {
    s.Lock()
    defer s.Unlock()
    s.count++
}

func (s *singleton) GetCount() int {
    s.RLock()
    defer s.RUnlock()
    return s.count
}

func main() {
    obj1 := GetInstance()
    obj1.AddOne()
    fmt.Println(obj1.GetCount())
    obj2 := GetInstance()
    obj2.AddOne()
    fmt.Println(obj2.GetCount())    
    obj3 := GetInstance()
    obj3.AddOne()
    fmt.Println(obj3.GetCount())
}

预期结果是:

1 2 3

因为您正在访问相同的资源。这就是我添加互斥锁的原因,以便能够从多个进程并发访问 count 属性。 :-)

来源:

https://play.golang.org/p/2XnLztX8Gs5

Easy peasy as you can see in the following code:

package main

import (
    "fmt"
    "sync"
)

type singleton struct {
    count int
    sync.RWMutex
}

var instance singleton 

func GetInstance() *singleton {
    return &instance 
}

func (s *singleton) AddOne() {
    s.Lock()
    defer s.Unlock()
    s.count++
}

func (s *singleton) GetCount() int {
    s.RLock()
    defer s.RUnlock()
    return s.count
}

func main() {
    obj1 := GetInstance()
    obj1.AddOne()
    fmt.Println(obj1.GetCount())
    obj2 := GetInstance()
    obj2.AddOne()
    fmt.Println(obj2.GetCount())    
    obj3 := GetInstance()
    obj3.AddOne()
    fmt.Println(obj3.GetCount())
}

Expected result would be:

1 2 3

Because you're accessing to the same resource. That's the reason I've added mutex in order to be concurrent proven accessing count attribute from multiple processes. :-)

Source:

https://play.golang.org/p/2XnLztX8Gs5

那支青花 2024-08-19 23:44:47

您可以使用 once 包 进行初始化:

这将确保您的 init 方法仅被调用一次。

You can do initialization using the once package:

This will ensure that your init methods only get called once.

莳間冲淡了誓言ζ 2024-08-19 23:44:47

只需拥有所需对象的单个静态、最终、常量、全局、应用程序范围实例即可。

然而,这与面向对象范式相矛盾。它的使用应仅限于基元和不可变对象,而不是可变对象。

Just have a single static, final, constant, global, application-wide instance of the Object you want.

This however contradicts the OO paradigm. Its use should be limited to primitives and immutable objects, not to mutable objects.

泛泛之交 2024-08-19 23:44:47

您应该知道 Once.Do 非常重视只执行一次代码。这意味着,代码总是只执行一次,即使它可能已经恐慌:

来自 https://golang.org/pkg/sync/#Once.Do

如果f(注意:once逻辑)发生恐慌,Do认为它已经返回;以后调用 Do 返回而不调用 f。

我使用互斥体来确保全局配置变量的唯一初始化,以克服此限制:

You should be aware that Once.Do is serious about executing the code only once. That means, the code is always executed only once, even though it might have panicked:

from https://golang.org/pkg/sync/#Once.Do

If f (note: the once logic) panics, Do considers it to have returned; future calls of Do return without calling f.

I used mutexes instead to ensure unique initialisation of a global configuration variable to overcome this restriction:

逆蝶 2024-08-19 23:44:47

我认为如果你想要 Go 中的单例之类的东西,你应该尝试思考你想要实现的目标。与 Java 或 C# 不同,Go 没有“静态”类的概念,因此传统的区别不太明确。在我看来,您希望从单例中获得的关键点是不允许其他人构建它。为此,我认为可以更简单地实现:导出一个接口,实现一个实现该接口的未导出类,然后导出它的单个实例。例如:

var DefaultTransformer Transformer = &transformer{}

type Transformer interface {
    Transform(s string) string
}

type transformer struct {
    
}

func (t *transformer) Transform(s string) string {
    return s + "1"
}

var _ Transformer = (*transformer)(nil)

正如其他答案所示,有很多更字面的方法可以在 Go 中实现单例模式,但它们让我觉得答案是从必须精确复制模式的前提开始的,而不是从解决实际的问题开始。你在 Go 中遇到的问题。

I think if you want something like a singleton in Go you should try and think about what you're trying to achieve. Unlike Java or C#, Go has no concept of "static" classes, so the traditional distinction is less clear. In my mind, the key point you'd want from a singleton is not allowing others to construct it. To that end, I think it can achieved more simply: export an interface, implement an unexported class which implements this interface, and export a single instance of it. For instance:

var DefaultTransformer Transformer = &transformer{}

type Transformer interface {
    Transform(s string) string
}

type transformer struct {
    
}

func (t *transformer) Transform(s string) string {
    return s + "1"
}

var _ Transformer = (*transformer)(nil)

As the other answers show, there are many more literal ways you can implement the singleton pattern in Go, but they strike me as answers that start from the premise that the pattern must be copied exactly, rather than starting from solving a real problem you have in Go.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文