iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >go sync.Once如何实现高效单例模式
  • 458
分享到

go sync.Once如何实现高效单例模式

2023-07-05 11:07:53 458人浏览 安东尼
摘要

这篇文章主要讲解了“Go sync.Once如何实现高效单例模式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“go sync.Once如何实现高效单例模式”吧!基本实现1

这篇文章主要讲解了“Go sync.Once如何实现高效单例模式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“go sync.Once如何实现高效单例模式”吧!

    基本实现

    1 单例模式定义

    单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点来访问这个实例。在整个应用程序中,所有对于这个类的访问都将返回同一个实例对象。

    2 sync.Once实现单例模式

    下面是一个简单的示例代码,使用 sync.Once 实现单例模式:

     package singleton import "sync" type singleton struct {     // 单例对象的状态 } var (     instance *singleton     once     sync.Once ) func GetInstance() *singleton {     once.Do(func() {         instance = &singleton{}         // 初始化单例对象的状态     })     return instance }

    在上面的示例代码中,我们定义了一个 singleton 结构体表示单例对象的状态,然后将它的实例作为一个包级别的变量 instance,并使用一个 once 变量来保证 GetInstance 函数只被执行一次。

    GetInstance 函数中,我们使用 once.Do 方法来执行一个初始化单例对象。由于 once.Do 方法是基于原子操作实现的,因此可以保证并发安全,即使有多个协程同时调用 GetInstance 函数,最终也只会创建一个对象。

    3 其他方式实现单例模式

    3.1 全局变量定义时赋值,实现单例模式

    在 Go 语言中,全局变量会在程序启动时自动初始化。因此,如果在定义全局变量时给它赋值,则对象的创建也会在程序启动时完成,可以通过此来实现单例模式,以下是一个示例代码:

    type MySingleton struct {    // 字段定义}var mySingletonInstance = &MySingleton{    // 初始化字段}func GetMySingletonInstance() *MySingleton {    return mySingletonInstance}

    在上面的代码中,我们定义了一个全局变量 mySingletonInstance 并在定义时进行了赋值,从而在程序启动时完成了对象的创建和初始化。在 GetMySingletonInstance 函数中,我们可以直接返回全局变量 mySingletonInstance,从而实现单例模式。

    3.2 init 函数实现单例模式

    在 Go 语言中,我们可以使用 init 函数来实现单例模式。init 函数是在包被加载时自动执行的函数,因此我们可以在其中创建并初始化单例对象,从而保证在程序启动时就完成对象的创建。以下是一个示例代码:

    package maintype MySingleton struct {    // 字段定义}var mySingletonInstance *MySingletonfunc init() {    mySingletonInstance = &MySingleton{        // 初始化字段    }}func GetMySingletonInstance() *MySingleton {    return mySingletonInstance}

    在上面的代码中,我们定义了一个包级别的全局变量 mySingletonInstance,并在 init 函数中创建并初始化了该对象。在 GetMySingletonInstance 函数中,我们直接返回该全局变量,从而实现单例模式。

    3.3 使用互斥实现单例模式

    在 Go 语言中,可以只使用一个互斥锁来实现单例模式。下面是一个简单代码的演示:

    var instance *MySingletonvar mu sync.Mutexfunc GetMySingletonInstance() *MySingleton {   mu.Lock()   defer mu.Unlock()   if instance == nil {      instance = &MySingleton{         // 初始化字段      }   }   return instance}

    在上面的代码中,我们使用了一个全局变量instance来存储单例对象,并使用了一个互斥锁 mu 来保证对象的创建和初始化。具体地,我们在 GetMySingletonInstance 函数中首先加锁,然后判断 instance 是否已经被创建,如果未被创建,则创建并初始化对象。最后,我们释放锁并返回单例对象。

    需要注意的是,在并发高的情况下,使用一个互斥锁来实现单例模式可能会导致性能问题。因为在一个 goroutine 获得锁并创建对象时,其他的 goroutine 都需要等待,这可能会导致程序变慢。

    4 使用sync.Once实现单例模式的优点

    相对于init 方法和使用全局变量定义赋值单例模式的实现,sync.Once 实现单例模式可以实现延迟初始化,即在第一次使用单例对象时才进行创建和初始化。这可以避免在程序启动时就进行对象的创建和初始化,以及可能造成的资源的浪费。

    而相对于使用互斥锁实现单例模式,使用 sync.Once 实现单例模式的优点在于更为简单和高效。sync.Once提供了一个简单的接口,只需要传递一个初始化函数即可。相比互斥锁实现方式需要手动处理锁、判断等操作,使用起来更加方便。而且使用互斥锁实现单例模式需要在每次访问单例对象时进行加锁和解锁操作,这会增加额外的开销。而使用 sync.Once 实现单例模式则可以避免这些开销,只需要在第一次访问单例对象时进行一次初始化操作即可。

    但是也不是说sync.Once便适合所有的场景,这个是需要具体情况具体分析的。下面说明sync.Onceinit方法,在哪些场景下使用init更好,在哪些场景下使用sync.Once更好。

    5 sync.Once和init方法适用场景

    对于init实现单例,比较适用于在程序启动时就需要初始化变量的场景。因为init函数是在程序运行前执行的,可以确保变量在程序运行时已经被初始化。

    对于需要延迟初始化某些对象,对象被创建出来并不会被马上使用,或者可能用不到,例如创建数据库连接池等。这时候使用sync.Once就非常合适。它可以保证对象只被初始化一次,并且在需要使用时才会被创建,避免不必要的资源浪费。

    gin中单例模式的使用

    1 背景

    这里首先需要介绍下gin.Engine, gin.Engine是Gin框架的核心组件,负责处理Http请求,路由请求到对应的处理器,处理器可以是中间件、控制器或处理HTTP响应等。每个gin.Engine实例都拥有自己的路由表、中间件栈和其他配置项,通过调用其方法可以注册路由、中间件、处理函数等。

    一个HTTP服务器,只会存在一个对应的gin.Engine实例,其保存了路由映射规则等内容。

    为了简化开发者Gin框架的使用,不需要用户创建gin.Engine实例,便能够完成路由的注册等操作,提高代码的可读性和可维护性,避免重复代码的出现。这里对于一些常用的功能,抽取出一些函数来使用,函数签名如下:

    // ginS/gins.go// 加载html模版文件func LoadHTMLGlob(pattern string) {}// 注册POST请求处理器func POST(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {}// 注册GET请求处理器func GET(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {}// 启动一个HTTP服务器func Run(addr ...string) (err error) {}// 等等...

    接下来需要对这些函数来进行实现。

    2 具体实现

    首先从使用出发,这里使用POST方法/GET方法注册请求处理器,然后使用Run方法启动服务器:

    func main() {   // 注册url对应的处理器   POST("/login", func(c *gin.Context) {})   // 注册url对应的处理器   GET("/hello", func(c *gin.Context) {})   // 启动服务   Run(":8080")}

    这里我们想要的效果,应该是调用Run方法启动服务后,往/login路径发送请求,此时应该执行我们注册的对应处理器,往/hello路径发送请求也是同理。

    所以,这里POST方法,GET方法,Run方法应该都是对同一个gin.Engine 进行操作的,而不是各自使用各自的gin.Engine实例,亦或者每次调用就创建一个gin.Engine实例。这样子才能达到我们预想的效果。

    所以,我们需要实现一个方法,获取gin.Engine实例,每次调用该方法都是获取到同一个实例,这个其实也就是单例的定义。然后POST方法,GET方法又或者是Run方法,调用该方法获取到gin.Engine实例,然后调用实例去调用对应的方法,完成url处理器的注册或者是服务的启动。这样子就能够保证是使用同一个gin.Engine实例了。具体实现如下:

    // ginS/gins.goimport (   "GitHub.com/gin-gonic/gin")var once sync.Oncevar internalEngine *gin.Enginefunc engine() *gin.Engine {   once.Do(func() {      internalEngine = gin.Default()   })   return internalEngine}// POST is a shortcut for router.Handle("POST", path, handle)func POST(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {   return engine().POST(relativePath, handlers...)}// GET is a shortcut for router.Handle("GET", path, handle)func GET(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes {   return engine().GET(relativePath, handlers...)}

    这里engine() 方法使用了 sync.Once 实现单例模式,确保每次调用该方法返回的都是同一个 gin.Engine 实例。然后POST/GET/Run方法通过该方法获取到gin.Engine实例,然后调用实例中对应的方法来完成对应的功能,从而达到POST/GET/Run等方法都是使用同一个实例操作的效果。

    3 sync.Once实现单例的好处

    这里想要达到的目的,其实是GET/POST/Run等抽取出来的函数,使用同一个gin.Engine实例。

    为了达到这个目的,我们其实可以在定义internalEngine 变量时,便对其进行赋值;或者是通init函数完成对internalEngine变量的赋值,其实都可以。

    但是我们抽取出来的函数,用户并不一定使用,定义时便初始化或者在init方法中便完成了对变量的赋值,用户没使用的话,创建出来的gin.Engine实例没有实际用途,造成了不必要的资源的浪费。

    而engine方法使用sync.Once实现了internalEngin的延迟初始化,只有在真正使用到internalEngine时,才会对其进行初始化,避免了不必要的资源的浪费。

    这里其实也印证了上面我们所说的sync.Once的适用场景,对于不会马上使用的单例对象,此时可以使用sync.Once来实现。

    感谢各位的阅读,以上就是“go sync.Once如何实现高效单例模式”的内容了,经过本文的学习后,相信大家对go sync.Once如何实现高效单例模式这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

    --结束END--

    本文标题: go sync.Once如何实现高效单例模式

    本文链接: https://www.lsjlt.com/news/351547.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • go sync.Once如何实现高效单例模式
      这篇文章主要讲解了“go sync.Once如何实现高效单例模式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“go sync.Once如何实现高效单例模式”吧!基本实现1...
      99+
      2023-07-05
    • go sync.Once实现高效单例模式详解
      目录1. 简介2. 基本实现2.1 单例模式定义2.2 sync.Once实现单例模式2.3 其他方式实现单例模式2.3.1 全局变量定义时赋值,实现单例模式2.3.2 init 函...
      99+
      2023-03-14
      go sync.Once单例模式 go sync.Once
    • Golang sync.Once实现单例模式的方法详解
      目录1. sync.Once 的原理和实现2. sync.Once 的错误处理3. sync.Once 的嵌套调用4. 并发性能5. 总结Go 语言的 sync 包提供了一系列同步原...
      99+
      2023-05-18
      Golang sync.Once实现单例模式 Golang sync.Once原理 Golang sync.Once使用 Golang sync.Once
    • 如何实现单例模式
      本篇文章给大家分享的是有关如何实现单例模式,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。header("Content-type:t...
      99+
      2024-04-02
    • JavaScript如何实现单例模式
      小编给大家分享一下JavaScript如何实现单例模式,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!单例模式通过 ES6 的 Proxy 拦截构造函数的执行方法来...
      99+
      2023-06-27
    • PHP单例模式如何实现
      这篇文章主要介绍“PHP单例模式如何实现”,在日常操作中,相信很多人在PHP单例模式如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PHP单例模式如何实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧...
      99+
      2023-07-04
    • Android如何实现单例模式
      这篇文章主要介绍了Android如何实现单例模式,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一.饿汉式public class SingletionSt...
      99+
      2023-06-15
    • java单例模式如何实现
      本篇内容主要讲解“java单例模式如何实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java单例模式如何实现”吧!0x01 宫女请安在朕的后宫中,皇后当之无愧的是天下第一(朕只能当...
      99+
      2023-06-19
    • Java的单例模式如何实现
      这篇文章主要介绍“Java的单例模式如何实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java的单例模式如何实现”文章能帮助大家解决问题。什么是单例模式单例模式(Singleton Patter...
      99+
      2023-06-27
    • 如何实现单例设计模式
      这篇文章主要讲解了“如何实现单例设计模式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何实现单例设计模式”吧! 单例模式单例模式(Singleton Pattern)是 Java...
      99+
      2023-06-15
    • Go单例模式与Once源码实现
      目录单例实现sync.Once源码分析1. lock并不会同步值2. Do执行一次3. Once执行Do后不准copy4. Do并发时阻塞5. Do递归死锁单例实现 type sin...
      99+
      2022-12-08
      go单例模式 go Once源码
    • Go语言单例模式怎么实现
      这篇文章主要介绍“Go语言单例模式怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Go语言单例模式怎么实现”文章能帮助大家解决问题。什么是单例模式单例模式指仅允许创建一个对象的设计模式。它通常...
      99+
      2023-07-05
    • spring的单例模式如何现实
      在Spring中,有多种方式来实现单例模式: 默认的单例模式:Spring容器默认情况下会将所有声明为Bean的对象作为单例对象...
      99+
      2024-02-29
      spring
    • js单例模式如何实现模态框
      这篇文章给大家分享的是有关js单例模式如何实现模态框的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。什么是单例呢?单,就是一个的意思。例:就是实例化出来的对象,那合在一起就是保证一...
      99+
      2024-04-02
    • java设计模式中如何实现单例模式
      这篇文章将为大家详细讲解有关java设计模式中如何实现单例模式,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。下面是一个简单的小实例://简单懒汉式 public class ...
      99+
      2023-05-30
      java
    • Java设计模式的单例模式如何实现
      这篇文章主要介绍了Java设计模式的单例模式如何实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java设计模式的单例模式如何实现文章都会有所收获,下面我们一起来看看吧。单例模式单例模式顾名思义就是单一的实例...
      99+
      2023-06-29
    • 如何使用Javascript实现单例模式
      这篇文章给大家分享的是有关如何使用Javascript实现单例模式的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。JavaScript是什么JavaScript是一种直译式的脚本语言,其解释器被称为JavaScri...
      99+
      2023-06-14
    • 在Python中如何实现单例模式
      本篇内容主要讲解“在Python中如何实现单例模式”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“在Python中如何实现单例模式”吧!方法一:使用装饰器实现单例模式。from functools...
      99+
      2023-06-01
    • Python实现单例模式
      1.什么是单例? 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。那么单例模式有什么用途呢?举个常见的单例模式例子,我们平时使用的电脑上都有一个回收站,在整个操作系统中,回...
      99+
      2023-01-31
      模式 Python
    • python3实现单例模式
      单例模式指确保某个类在整个系统中只存在一个实例的一种设计模式使用单例模式的好处:1、每个实例都会占用一定的内存资源,且初始化实例时会影响运行性能,所以当整个系统只需一个实例时,使用单例模式不仅可减少资源占用,而且因为只初始化一次,还可以加...
      99+
      2023-01-31
      模式
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作