-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
97 lines (55 loc) · 34.1 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Yu</title>
<subtitle>Jarrem</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://tangshiyu.github.io/"/>
<updated>2020-02-18T03:24:44.085Z</updated>
<id>https://tangshiyu.github.io/</id>
<author>
<name>Yu</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>Golang 中的 goroutine 简单理解和使用</title>
<link href="https://tangshiyu.github.io/2020/02/16/Go/goroutine/goroutine/"/>
<id>https://tangshiyu.github.io/2020/02/16/Go/goroutine/goroutine/</id>
<published>2020-02-16T02:22:56.000Z</published>
<updated>2020-02-18T03:24:44.085Z</updated>
<content type="html"><![CDATA[<h2><span id="什么是goroutine">什么是goroutine</span></h2><h3><span id="相关概念">相关概念</span></h3><ul><li><p>进程</p><p>进程是系统进行资源分配的和调度的基本单元,具有独立功能的程序在某个数据集合上的一次执行过程</p></li><li><p>线程</p></li></ul><p> 线程是进程的一个执行实体或者执行单元,是比进程更小的且能独立运行的基本单元,一个进程至少会有一个线程</p><ul><li><p>协程</p><p>协程又被称作为微协程,纤程。</p><p>协程相对独立有自己的上下文,由线程拉起,和线程相比协程避免了无意义的调度因此提高了性能,协程相对线程而言节约的是CPU的切换时间,但需要开发人员自己通过代码去调度kong</p></li><li><p>goroutine</p></li></ul><p> goroutine是Go语言的协程实现,从调度上讲goroutine的调度开销远远小于线程调度开销,不同的是Go在runtime和系统调用等方面对goroutine做了封装处理,goroutine不完全是受开发人员控制,一定程度上由Go runtime管理, 当某个goroutine受阻塞时,会让出CPU资源给其他的goroutine, Golang 的一大特色就是从语言层面原生支持协程,在函数或者方法前面加 go关键字就可创建一个协程。</p><h2><span id="csp并发模型">CSP并发模型</span></h2><p> 这里简单介绍下CSP,后面专门写一篇详细介绍CSP模型, CSP(communicating sequential processes)它不同与多线程通过共享内存来通信,像Java中共享内存通信时需要考虑线程安全问题,<code>原子性</code>、<code>有序性</code>、<code>可见性</code>。CSP模型讲究的是通过通信来共享内存,这也是Go语言特有的并发模型,CSP模型主要通过Go的goroutine和channel来实现。</p><h2><span id="gpm模型">GPM模型</span></h2><p>这里也是简单了解和介绍,后面将详细介绍</p><p>G: Goroutine ,本质上一种轻量级的线程</p><p>P: Processor, 代表了M所需要上下文环境,处理用户级代码逻辑的处理器,这里是一个抽象的概念并非真正的CPU,当P有任务时需要创建或者唤醒一个系统线程来执行它队列里面任务,所以需要P与M的绑定形成一个执行单元</p><p>M: Machine, 关联系统的一个内核线程,每次创建一个M时候都会有一个底层线程创建,所有的G任务最后都是在G上面运行</p><p>它们之间的关系如下:</p><p> 一个M(Machine)对应一个系统内核线程,也会连接一个上下文P(Processor),一个上下文P会关联多个G(Goroutine )</p><h2><span id="goroutine实际应用">goroutine实际应用</span></h2><p> Go的并发写起来非常容器不像其他语言,只需要一个go关键字就可以搞定,例如:<code>go work()</code>, 在启动一个goroutine,一定需要知道它时何时关闭的,并且要节约使用,考虑它的必要性避免滥用,使用goroutine会给程序带来风险特别是死锁,对于后面问题排除也会带来很大的麻烦</p><h3><span id="syncwaitgroup">sync.WaitGroup</span></h3><p> 当我们启动一个goroutine时候,我们必须考虑它何时结束,但运行时间较长的时候,不做任何操作,这时候如果main主进程运行结束,会导致进程直接退出,不会考虑启动的goroutine有没有结束,甚至可能goroutine还没有起来,main已经运行完了,有必要的时候需要等待启动的goroutine运行完再退出,有人可能马上想到用sleep的方式,sleep不能准确估计goroutine运行时间,甚至可能会导致进程一直卡住,这里我们需要一个管理者,这个管理者就是sync.WaitGroup</p><p>案例代码如下:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"> <span class="string">"fmt"</span></span><br><span class="line"> <span class="string">"sync"</span></span><br><span class="line"> <span class="string">"time"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">work</span><span class="params">(data <span class="keyword">int</span>)</span></span> {</span><br><span class="line"> fmt.Println(data)</span><br><span class="line"> time.Sleep(time.Duration(<span class="number">1</span>) * time.Second)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"> gNum := <span class="number">5</span></span><br><span class="line"> <span class="keyword">var</span> wg = sync.WaitGroup{}</span><br><span class="line"> wg.Add(gNum)</span><br><span class="line"> <span class="keyword">for</span> i := <span class="number">1</span>; i <= gNum; i++ {</span><br><span class="line"> <span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">(w sync.WaitGroup, data <span class="keyword">int</span>)</span></span> {</span><br><span class="line"> work(data)</span><br><span class="line"> wg.Done()</span><br><span class="line"> }(wg, i)</span><br><span class="line"> }</span><br><span class="line"> wg.Wait()</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>运行结果如下:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">5</span><br><span class="line">1</span><br><span class="line">2</span><br><span class="line">4</span><br><span class="line">3</span><br><span class="line"></span><br><span class="line">Process finished with exit code 0</span><br></pre></td></tr></table></figure><p>使用的时候一定要保证设置等待的goroutine,最后一定要Done关闭掉不然就会导致死锁</p><h3><span id="使用channel传递信息">使用channel传递信息</span></h3><p> channle一定得小心使用,一定不要滥用,channel使用不当很容器造成死锁,并且channel使用注意以下几点</p><ul><li>不能往关闭的channle发消息</li><li>不能只发消息或者不能只接受消息,只在单一的goroutine里操作无缓冲信道,一定会死锁,例如下面代码中的订阅者,如果不加超时机制,如果发布者关闭或者退出了订阅者等待的消息永远等不到就会造成死锁</li><li>两个通道依赖使用,一个通道的输出作为另外一个通道的输入,例如<code>c1<-<-c2</code>,这个很容易造成两个goroutine等待变成死锁</li></ul><p>简单的发布订阅通过channel实现如下:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">"fmt"</span></span><br><span class="line"><span class="string">"sync"</span></span><br><span class="line"><span class="string">"time"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 简单的发布订阅,通过channel实现</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Publisher <span class="keyword">struct</span> {</span><br><span class="line">PubMsg <span class="keyword">chan</span> <span class="keyword">string</span></span><br><span class="line">StopSignal <span class="keyword">chan</span> <span class="keyword">bool</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 发布者</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">publish</span><span class="params">(p Publisher, w *sync.WaitGroup)</span></span> {</span><br><span class="line">duration := time.Duration(<span class="number">1</span>) * time.Second</span><br><span class="line">tick := time.NewTicker(duration)</span><br><span class="line"><span class="keyword">var</span> msgCnt = <span class="number">0</span></span><br><span class="line"><span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> {</span><br><span class="line">fmt.Println(<span class="string">"publisher will exit......."</span>)</span><br><span class="line">tick.Stop()</span><br><span class="line">w.Done()</span><br><span class="line">}()</span><br><span class="line"><span class="keyword">for</span> {</span><br><span class="line"><span class="keyword">select</span> {</span><br><span class="line"><span class="keyword">case</span> <-tick.C:</span><br><span class="line"><span class="comment">// 每秒发布一条消息</span></span><br><span class="line">p.PubMsg <- fmt.Sprintf(<span class="string">"消息-%d"</span>, msgCnt)</span><br><span class="line">msgCnt++</span><br><span class="line"></span><br><span class="line"><span class="comment">// 这里模拟关闭发布者</span></span><br><span class="line"><span class="keyword">if</span> msgCnt >= <span class="number">5</span> {</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">case</span> <-p.StopSignal:</span><br><span class="line">fmt.Println(<span class="string">"收到停止发送信号,将关闭publish..."</span>)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 订阅者</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">subscriber</span><span class="params">(p Publisher, w *sync.WaitGroup)</span></span> {</span><br><span class="line">d := time.Duration(<span class="number">2</span>) * time.Second</span><br><span class="line">timeout := time.NewTimer(d)</span><br><span class="line"><span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> {</span><br><span class="line">fmt.Println(<span class="string">"subscriber will exit......."</span>)</span><br><span class="line">timeout.Stop()</span><br><span class="line">w.Done()</span><br><span class="line">}()</span><br><span class="line"><span class="keyword">for</span> {</span><br><span class="line"><span class="keyword">select</span> {</span><br><span class="line"><span class="keyword">case</span> msg := <-p.PubMsg:</span><br><span class="line">fmt.Printf(<span class="string">"收到订阅消息:%s\n"</span>, msg)</span><br><span class="line">timeout.Reset(d)</span><br><span class="line"><span class="comment">// 设置收取消息超时防止死锁</span></span><br><span class="line"><span class="keyword">case</span> <-timeout.C:</span><br><span class="line">fmt.Println(<span class="string">"收取消息超时!!!"</span>)</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"><span class="comment">// 消息通道</span></span><br><span class="line">msgChan := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">string</span>)</span><br><span class="line"><span class="comment">// 停止信号通道</span></span><br><span class="line">singleChan := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">bool</span>)</span><br><span class="line">publisher := Publisher{msgChan, singleChan}</span><br><span class="line">wg := &sync.WaitGroup{}</span><br><span class="line"></span><br><span class="line">wg.Add(<span class="number">2</span>)</span><br><span class="line"><span class="keyword">go</span> publish(publisher, wg)</span><br><span class="line"><span class="keyword">go</span> subscriber(publisher, wg)</span><br><span class="line">wg.Wait()</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2><span id="总结">总结</span></h2><p>goroutine本质是协程,也是Go实现并行的核心,用起来比较简单,但是用好它不太容易,使用时一定要设计好,考虑是否一定要用它。</p>]]></content>
<summary type="html">
<h2><span id="什么是goroutine">什么是goroutine</span></h2><h3><span id="相关概念">相关概念</span></h3><ul>
<li><p>进程</p>
<p>进程是系统进行资源分配的和调度的基本单元,具有独立功能的程序
</summary>
<category term="Go" scheme="https://tangshiyu.github.io/categories/Go/"/>
<category term="Go" scheme="https://tangshiyu.github.io/tags/Go/"/>
</entry>
<entry>
<title>代理模式</title>
<link href="https://tangshiyu.github.io/2020/02/15/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F/proxy/"/>
<id>https://tangshiyu.github.io/2020/02/15/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F/proxy/</id>
<published>2020-02-15T02:08:40.000Z</published>
<updated>2020-02-17T09:13:29.736Z</updated>
<content type="html"><![CDATA[<p> 代理模式为其他对象提供一种代理以控制对这个对象的访问权限,它主要解决直接访问对象带来的问题,例如公司环境访问通过堡垒机代理访问生产环境权限,避免了生成环境权限全部开发的局面,只需要开放相应的权限给开发者即可,注意它不需要更改原始接口的内容</p><p> 例如下面堡垒机,在原始虚拟机VM上做权限控制和审计功能</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"> <span class="string">"errors"</span></span><br><span class="line"> <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 原始虚拟机拥有读写和执行权限</span></span><br><span class="line"><span class="keyword">type</span> VM <span class="keyword">struct</span> {</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(vm *VM)</span> <span class="title">Write</span><span class="params">()</span></span> {</span><br><span class="line"> fmt.Println(<span class="string">"Permission to write...."</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(vm *VM)</span> <span class="title">Read</span><span class="params">()</span></span> {</span><br><span class="line"> fmt.Println(<span class="string">"Permission to Read....."</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(vm *VM)</span> <span class="title">execute</span><span class="params">()</span></span> {</span><br><span class="line"> fmt.Println(<span class="string">"Permission to execute....."</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 堡垒机</span></span><br><span class="line"><span class="keyword">type</span> AccessGateway <span class="keyword">struct</span> {</span><br><span class="line"> v *VM</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 堡垒机可以做相关权限控制,和审计功能</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewAccessGateWay</span><span class="params">(username <span class="keyword">string</span>)</span> <span class="params">(*AccessGateway, error)</span></span> {</span><br><span class="line"> <span class="keyword">if</span> username != <span class="string">"Yu"</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, errors.New(<span class="string">"Username not enough permissions"</span>)</span><br><span class="line"> }</span><br><span class="line"> fmt.Printf(<span class="string">"[%s] login into access gate wasy......\n"</span>, username)</span><br><span class="line"> <span class="keyword">return</span> &AccessGateway{&VM{}}, <span class="literal">nil</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(ag *AccessGateway)</span> <span class="title">Read</span><span class="params">()</span></span> {</span><br><span class="line"> ag.v.Read()</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(ag *AccessGateway)</span> <span class="title">Write</span><span class="params">()</span></span> {</span><br><span class="line"> ag.v.Write()</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"> <span class="keyword">var</span> accessGateway, err = NewAccessGateWay(<span class="string">"Yu"</span>)</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> fmt.Printf(<span class="string">"Login into access gateway meet err! %v"</span>, err)</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"> }</span><br><span class="line"> accessGateway.Write()</span><br><span class="line"> accessGateway.Read()</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>输出结果如下:</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[<span class="type">Yu</span>] login into access gate wasy......</span><br><span class="line">Permission to write....</span><br><span class="line">Permission to Read.....</span><br><span class="line"></span><br><span class="line"><span class="keyword">Process</span> finished with <span class="keyword">exit</span> code <span class="number">0</span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p> 代理模式为其他对象提供一种代理以控制对这个对象的访问权限,它主要解决直接访问对象带来的问题,例如公司环境访问通过堡垒机代理访问生产环境权限,避免了生成环境权限全部开发的局面,只需要开放相应的权限给开发者即可,注意它不需要更改原始接口的内容</p>
<p>
</summary>
<category term="设计模式" scheme="https://tangshiyu.github.io/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="设计模式" scheme="https://tangshiyu.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
</entry>
<entry>
<title>单例模式</title>
<link href="https://tangshiyu.github.io/2020/02/13/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/singleton/"/>
<id>https://tangshiyu.github.io/2020/02/13/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/singleton/</id>
<published>2020-02-13T04:08:40.000Z</published>
<updated>2020-02-17T09:13:29.739Z</updated>
<content type="html"><![CDATA[<p><img src="./test.png" alt="test"></p><p>单例模式是我们平常开发中用的最多设计模式之一,单例有很多级别上的,例如函数上的单例,进程上的单例,下面讲的是代码中的单例,只要了解单例的思想即可,语言知识实现工具,下面讲解如下几种类型单例模式</p><ul><li>饿汉模式</li><li>懒汉模式</li><li>懒汉模式(加锁)</li><li>懒汉模式(双重检查加锁)</li><li>sync.Once实现</li></ul><p>相关代码如下:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">"fmt"</span></span><br><span class="line"><span class="string">"sync"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> SingleTon <span class="keyword">struct</span> {</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> singleTon *SingleTon</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> mu sync.Mutex</span><br><span class="line"></span><br><span class="line"><span class="comment">//懒汉模式</span></span><br><span class="line"><span class="comment">//还有一种饿汉式,就是一开始就初始化singleTon,实现如下</span></span><br><span class="line"><span class="comment">//func init() {</span></span><br><span class="line"><span class="comment">// singleTon = &SingleTon{}</span></span><br><span class="line"><span class="comment">//}</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewSingleTon</span><span class="params">()</span> *<span class="title">SingleTon</span></span> {</span><br><span class="line"> <span class="keyword">if</span> singleTon == <span class="literal">nil</span> {</span><br><span class="line"> singleTon = &SingleTon{}</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> singleTon</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 懒汉加锁</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewSingleTonByLock</span><span class="params">()</span> *<span class="title">SingleTon</span></span> {</span><br><span class="line"> mu.Lock()</span><br><span class="line"> <span class="keyword">defer</span> mu.Unlock()</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> singleTon == <span class="literal">nil</span> {</span><br><span class="line"> singleTon = &SingleTon{}</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> singleTon</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 懒汉加检查锁</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewSingleTonByLock2</span><span class="params">()</span> *<span class="title">SingleTon</span></span> {</span><br><span class="line"> <span class="keyword">if</span> singleTon == <span class="literal">nil</span> {</span><br><span class="line"> mu.Lock()</span><br><span class="line"> <span class="keyword">defer</span> mu.Unlock()</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> singleTon == <span class="literal">nil</span> {</span><br><span class="line"> singleTon = &SingleTon{}</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> singleTon</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 通过sync.Once实现</span></span><br><span class="line"><span class="comment">// 看过Once包的知道,实现很简单通过加锁实现,通过done标记位来判断,运行过一次通过原子操作将done置为1</span></span><br><span class="line"><span class="keyword">var</span> once sync.Once</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewSingleTonByOnce</span><span class="params">()</span> *<span class="title">SingleTon</span></span> {</span><br><span class="line"> once.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> {</span><br><span class="line"> singleTon = &SingleTon{}</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> singleTon</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
单例模式通过Go来实现
</summary>
<category term="设计模式" scheme="https://tangshiyu.github.io/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="设计模式" scheme="https://tangshiyu.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
</entry>
</feed>