You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

369 lines
14 KiB
HTML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="zh-cn" dir="ltr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content=" 一次性操作 - sync.Once # sync.Once用来完成一次性操作比如配置加载单例对象初始化等。
源码分析 # sync.Once定义如下
type Once struct { done uint32 // 用来标志操作是否操作 m Mutex // 锁,用来第一操作时候,加锁处理 } 接下来看剩下的全部代码:
func (o *Once) Do(f func()) { if atomic.LoadUint32(&amp;o.done) == 0 {// 原子性加载o.done若值为1说明已完成操作若为0说明未完成操作 o.doSlow(f) } } func (o *Once) doSlow(f func()) { o.m.Lock() // 加锁 defer o.m.Unlock() if o.done == 0 { // 再次进行o.done是否等于0判断因为存在并发调用doSlow的情况 defer atomic.StoreUint32(&amp;o.done, 1) // 将o.done值设置为1用来标志操作完成 f() // 执行操作 } } ">
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#ffffff">
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#343a40">
<meta name="color-scheme" content="light dark"><meta property="og:title" content="一次性操作 - sync.Once" />
<meta property="og:description" content=" 一次性操作 - sync.Once # sync.Once用来完成一次性操作比如配置加载单例对象初始化等。
源码分析 # sync.Once定义如下
type Once struct { done uint32 // 用来标志操作是否操作 m Mutex // 锁,用来第一操作时候,加锁处理 } 接下来看剩下的全部代码:
func (o *Once) Do(f func()) { if atomic.LoadUint32(&amp;o.done) == 0 {// 原子性加载o.done若值为1说明已完成操作若为0说明未完成操作 o.doSlow(f) } } func (o *Once) doSlow(f func()) { o.m.Lock() // 加锁 defer o.m.Unlock() if o.done == 0 { // 再次进行o.done是否等于0判断因为存在并发调用doSlow的情况 defer atomic.StoreUint32(&amp;o.done, 1) // 将o.done值设置为1用来标志操作完成 f() // 执行操作 } } " />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://go.cyub.vip/concurrency/sync-once/" /><meta property="article:section" content="concurrency" />
<title>一次性操作 - sync.Once | 深入Go语言之旅</title>
<link rel="manifest" href="/manifest.json">
<link rel="icon" href="/favicon.png" >
<link rel="stylesheet" href="/book.min.f06572240ce28e67eb332ac5cf5d59a696c47ad4c6f700d5842c5ed93dd8ec77.css" integrity="sha256-8GVyJAzijmfrMyrFz11ZppbEetTG9wDVhCxe2T3Y7Hc=" crossorigin="anonymous">
<script defer src="/flexsearch.min.js"></script>
<script defer src="/en.search.min.7e9d53d4a20eea8c87bf76a4502bd21aa041c1ef2adc7e37ffc5339c57accccd.js" integrity="sha256-fp1T1KIO6oyHv3akUCvSGqBBwe8q3H43/8UznFeszM0=" crossorigin="anonymous"></script>
<!--
Made with Book Theme
https://github.com/alex-shpak/hugo-book
-->
</head>
<body dir="ltr">
<input type="checkbox" class="hidden toggle" id="menu-control" />
<input type="checkbox" class="hidden toggle" id="toc-control" />
<main class="container flex">
<aside class="book-menu">
<div class="book-menu-content">
<nav>
<h2 class="book-brand">
<a class="flex align-center" href="/"><img src="https://static.cyub.vip/images/202310/golang-480.png" alt="Logo" /><span>深入Go语言之旅</span>
</a>
</h2>
<div class="book-search">
<input type="text" id="book-search-input" placeholder="Search" aria-label="Search" maxlength="64" data-hotkeys="s/" />
<div class="book-search-spinner hidden"></div>
<ul id="book-search-results"></ul>
</div>
<ul>
<li>
<a href="https://www.cyub.vip/" target="_blank" rel="noopener">
个人博客
</a>
</li>
<li>
<a href="https://github.com/cyub" target="_blank" rel="noopener">
Github主页
</a>
</li>
<li>
<a href="https://www.topgoer.cn/?ref=go.cyub.vip" target="_blank" rel="noopener">
地鼠文档
</a>
</li>
</ul>
<ul>
<li>
<p><strong>准备篇</strong></p>
<ul>
<li>
<a href="/compiler/">编译流程</a></li>
<li>
<a href="/analysis-tools/">分析工具</a>
<ul>
<li>
<a href="/analysis-tools/gdb/">GDB</a></li>
<li>
<a href="/analysis-tools/dlv/">Delve</a></li>
<li>
<a href="/analysis-tools/go-buildin-tools/">Go 内置工具</a></li>
</ul>
</li>
<li>
<a href="/go-assembly/">Go汇编</a></li>
</ul>
</li>
<li>
<p><strong>基础篇</strong></p>
<ul>
<li>
<a href="/type/">数据类型与数据结构</a>
<ul>
<li>
<a href="/type/string/">字符串</a></li>
<li>
<a href="/type/array/">数组</a></li>
<li>
<a href="/type/slice/">切片</a></li>
<li>
<a href="/type/nil/">nil</a></li>
<li>
<a href="/type/empty_struct/">空结构体</a></li>
<li>
<a href="/type/pointer/">指针</a></li>
<li>
<a href="/type/map/">映射</a></li>
</ul>
</li>
<li>
<a href="/function/">函数</a>
<ul>
<li>
<a href="/function/first-class/">一等公民</a></li>
<li>
<a href="/function/call-stack/">函数调用栈</a></li>
<li>
<a href="/function/pass-by-value/">值传递</a></li>
<li>
<a href="/function/closure/">闭包</a></li>
<li>
<a href="/function/method/">方法</a></li>
</ul>
</li>
<li>
<a href="/feature/">语言特性</a>
<ul>
<li>
<a href="/feature/comma-ok/">逗号ok模式</a></li>
<li>
<a href="/feature/for-range/">遍历 - for-range语法</a></li>
<li>
<a href="/feature/defer/">延迟执行 - defer语法</a></li>
<li>
<a href="/feature/select/">通道选择器 - select语法</a></li>
<li>
<a href="/feature/panic-recover/">恐慌与恢复 - panic/recover</a></li>
</ul>
</li>
</ul>
</li>
<li>
<p><strong>运行时篇</strong></p>
<ul>
<li>
<a href="/concurrency/">并发编程</a>
<ul>
<li>
<a href="/concurrency/memory-model/">内存模型</a></li>
<li>
<a href="/concurrency/context/">上下文 - context</a></li>
<li>
<a href="/concurrency/channel/">通道 - channel</a></li>
<li>
<a href="/concurrency/atomic/">原子操作 - atomic</a></li>
<li>
<a href="/concurrency/sync-map/">并发Map - sync.Map</a></li>
<li>
<a href="/concurrency/sync-waitgroup/">等待组 - sync.WaitGroup</a></li>
<li>
<a href="/concurrency/sync-once/"class=active>一次性操作 - sync.Once</a></li>
<li>
<a href="/concurrency/sync-pool/">缓冲池 - sync.Pool</a></li>
<li>
<a href="/concurrency/sync-cond/">条件变量 - sync.Cond</a></li>
<li>
<a href="/concurrency/sync-mutex/">互斥锁 - sync.Mutex</a></li>
<li>
<a href="/concurrency/sync-rwmutex/">读写锁 - sync.RWMutex</a></li>
</ul>
</li>
<li>
<a href="/gmp/">G-M-P调度机制</a>
<ul>
<li>
<a href="/gmp/gmp-model/">调度机制概述</a></li>
<li>
<a href="/gmp/scheduler/">调度器</a></li>
</ul>
</li>
<li>
<a href="/memory/">内存管理</a>
<ul>
<li>
<a href="/memory/allocator/">内存分配器</a></li>
<li>
<a href="/memory/gc/">GC</a></li>
</ul>
</li>
<li>
<a href="/type-system/">类型系统</a>
<ul>
<li>
<a href="/type-system/type/">类型系统</a></li>
<li>
<a href="/type-system/interface/">接口</a></li>
<li>
<a href="/type-system/reflect/">反射</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
<script>(function(){var e=document.querySelector("aside .book-menu-content");addEventListener("beforeunload",function(){localStorage.setItem("menu.scrollTop",e.scrollTop)}),e.scrollTop=localStorage.getItem("menu.scrollTop")})()</script>
</div>
</aside>
<div class="book-page">
<header class="book-header">
<div class="flex align-center justify-between">
<label for="menu-control">
<img src="/svg/menu.svg" class="book-icon" alt="Menu" />
</label>
<strong>一次性操作 - sync.Once</strong>
<label for="toc-control">
</label>
</div>
</header>
<article class="markdown"><h1 id="一次性操作---synconce">
一次性操作 - sync.Once
<a class="anchor" href="#%e4%b8%80%e6%ac%a1%e6%80%a7%e6%93%8d%e4%bd%9c---synconce">#</a>
</h1>
<p>sync.Once用来完成一次性操作比如配置加载单例对象初始化等。</p>
<h2 id="源码分析">
源码分析
<a class="anchor" href="#%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90">#</a>
</h2>
<p>sync.Once定义如下</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Once</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">done</span> <span style="color:#66d9ef">uint32</span> <span style="color:#75715e">// 用来标志操作是否操作
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">m</span> <span style="color:#a6e22e">Mutex</span> <span style="color:#75715e">// 锁,用来第一操作时候,加锁处理
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>}
</span></span></code></pre></div><p>接下来看剩下的全部代码:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">o</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Once</span>) <span style="color:#a6e22e">Do</span>(<span style="color:#a6e22e">f</span> <span style="color:#66d9ef">func</span>()) {
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">atomic</span>.<span style="color:#a6e22e">LoadUint32</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">o</span>.<span style="color:#a6e22e">done</span>) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> {<span style="color:#75715e">// 原子性加载o.done若值为1说明已完成操作若为0说明未完成操作
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">o</span>.<span style="color:#a6e22e">doSlow</span>(<span style="color:#a6e22e">f</span>)
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">o</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Once</span>) <span style="color:#a6e22e">doSlow</span>(<span style="color:#a6e22e">f</span> <span style="color:#66d9ef">func</span>()) {
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">o</span>.<span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">Lock</span>() <span style="color:#75715e">// 加锁
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">o</span>.<span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">Unlock</span>()
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">o</span>.<span style="color:#a6e22e">done</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> { <span style="color:#75715e">// 再次进行o.done是否等于0判断因为存在并发调用doSlow的情况
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">atomic</span>.<span style="color:#a6e22e">StoreUint32</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">o</span>.<span style="color:#a6e22e">done</span>, <span style="color:#ae81ff">1</span>) <span style="color:#75715e">// 将o.done值设置为1用来标志操作完成
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> <span style="color:#a6e22e">f</span>() <span style="color:#75715e">// 执行操作
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div></article>
<footer class="book-footer">
<div class="flex flex-wrap justify-between">
</div>
<script>(function(){function e(e){const t=window.getSelection(),n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}document.querySelectorAll("pre code").forEach(t=>{t.addEventListener("click",function(){if(window.getSelection().toString())return;e(t.parentElement),navigator.clipboard&&navigator.clipboard.writeText(t.parentElement.textContent)})})})()</script>
</footer>
<div class="book-comments">
<div id="disqus_thread"></div>
<script type="application/javascript">
window.disqus_config = function () {
};
(function() {
if (["localhost", "127.0.0.1"].indexOf(window.location.hostname) != -1) {
document.getElementById('disqus_thread').innerHTML = 'Disqus comments not available by default when the website is previewed locally.';
return;
}
var d = document, s = d.createElement('script'); s.async = true;
s.src = '//' + "go-cyub-vip" + '.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="https://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
</div>
<label for="menu-control" class="hidden book-menu-overlay"></label>
</div>
</main>
</body>
</html>