<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                這篇博客我們繼續來看設計模式,今天帶來的是一個最簡單而且最常用的模式-單例模式。那什么是單例模式呢?相信大家最它最熟悉不過了,那我們就來快速的了解一下它的定義。 ~~~ 保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。 ~~~ 這個解釋足夠簡單。說白了就是假如我們希望我們在我們的系統中該類僅僅存在1個或0個該類的實例。雖然單例模式很簡單,但是熟悉java的同學可能了解,單例模式有很多寫法,懶漢式、餓漢式、雙重鎖。。。 這么多形式,難道有什么目的?確實,不過他們的目的很明確,就是保證在一種特殊情況下的單例-并發。 ok,既然了解了單例模式,那下面我們就開始用代碼描述一下單例模式。首先是最簡單的單例,這里我們并不去考慮并發的情況。` ~~~ package manager import ( "fmt" ) var m *Manager func GetInstance() *Manager { if m == nil { m = &Manager {} } return m } type Manager struct {} func (p Manager) Manage() { fmt.Println("manage...") } ~~~ 這就是一個最簡單的單例了,對于Manager結構體,我們提供了一個GetInstance函數去獲取它的實例,這個函數中首先去判斷m變量是否為空,如果為空才去賦值一個Manager的指針類型的值,一個小小的判斷,就保證了我們在第第二次調用GetInstance的時候直接返回m,而不是重新獲取Manager的實例,進而保證了唯一實例。 上面的代碼確實簡單,也實現了最簡單的單例模式,不過大家有沒有考慮到并發這一點,在并發的情況下,這里是不是還可以正常工作呢? 來,先跟著下面的思路走一走,來看看問題出現在哪。 ~~~ 現在我們是在并發的情況下去調用的 GetInstance函數,現在恰好第一個goroutine執行到m = &Manager {}這句話之前,第二個goroutine也來獲取實例了,第二個goroutine去判斷m是不是nil,因為m = &Manager{}還沒有來得及執行,所以m肯定是nil,現在出現的問題就是if中的語句可能會執行兩遍! ~~~ 在上面介紹的這種情形中,因為m = &Manager{}可能會執行多次,所以我們寫的單例失效了,這個時候我們就該考慮為我們的單例加鎖啦。 這個時候我們就需要引入go的鎖機制-sync.Mutex了,修改我們的代碼, ~~~ package manager import ( "sync" "fmt" ) var m *Manager var lock *sync.Mutex = &sync.Mutex {} func GetInstance() *Manager { lock.Lock() defer lock.Unlock() if m == nil { m = &Manager {} } return m } type Manager struct {} func (p Manager) Manage() { fmt.Println("manage...") } ~~~ 代碼做了簡單的修改了,引入了鎖的機制,在GetInstance函數中,每次調用我們都會上一把鎖,保證只有一個goroutine執行它,這個時候并發的問題就解決了。不過現在不管什么情況下都會上一把鎖,而且加鎖的代價是很大的,有沒有辦法繼續對我們的代碼進行進一步的優化呢? 熟悉java的同學可能早就想到了雙重的概念,沒錯,在go中我們也可以使用雙重鎖機制來提高效率。 ~~~ package manager import ( "sync" "fmt" ) var m *Manager var lock *sync.Mutex = &sync.Mutex {} func GetInstance() *Manager { if m == nil { lock.Lock() defer lock.Unlock() if m == nil { m = &Manager {} } } return m } type Manager struct {} func (p Manager) Manage() { fmt.Println("manage...") } ~~~ 代碼只是稍作修改而已,不過我們用了兩個判斷,而且我們將同步鎖放在了條件判斷之后,這樣做就避免了每次調用都加鎖,提高了代碼的執行效率。 這獲取就是很完美的單例代碼了,不過還沒完,在go中我們還有更優雅的方式去實現。單例的目的是啥?保證實例化的代碼只執行一次,在go中就中這么一種機制來保證代碼只執行一次,而且不需要我們手工去加鎖解鎖。對,就是我們的sync.Once,它有一個Do方法,在它中的函數go會只保證僅僅調用一次!再次修改我們的代碼, ~~~ package manager import ( "sync" "fmt" ) var m *Manager var once sync.Once func GetInstance() *Manager { once.Do(func() { m = &Manager {} }) return m } type Manager struct {} func (p Manager) Manage() { fmt.Println("manage...") } ~~~ 代碼更簡單了,而且有沒有發現-漂亮了!Once.Do方法的參數是一個函數,這里我們給的是一個匿名函數,在這個函數中我們做的工作很簡單,就是去賦值m變量,而且go能保證這個函數中的代碼僅僅執行一次! ok,到現在單例模式我們就介紹完了,內容并不多,因為單例模式太簡單而且太常見了。我們用單例的目的是為了保證在整個系統中存在唯一的實例,我們加鎖的目的是為了在并發的環境中單例依舊好用。不過雖然單例簡單,我們還是不能任性的用,因為這樣做實例會一直存在內存中,一些我們用的不是那么頻繁的東西使用了單例是不是就造成了內存的浪費?大家在用單例的時候還是要多思考思考,這個模塊適不適合用單例! 原文:http://blog.csdn.net/qibin0506/article/details/50733314 ![](https://box.kancloud.cn/032176b8778dbc41f1ce6b79a83d59c1_900x350.jpg)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看