> For the complete documentation index, see [llms.txt](https://wtifs.gitbook.io/diva-notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wtifs.gitbook.io/diva-notes/go/5.-bing-fa-bian-cheng/24.sync.once-de-shi-xian.md).

# 2-4.sync.Once的实现

Go 语言标准库中 [`sync.Once`](https://draveness.me/golang/tree/sync.Once) 可以保证在 Go 程序运行期间的某段代码只会执行一次。

其原理也很简单：用一个数字表示是否执行过 + 锁保证并发场景下只执行一次。后续再次执行时，检查该变量即可。

```go
type Once struct {
    done uint32 // 用来标识代码块是否执行过
    m    Mutex  // 互斥锁
}

func (o *Once) Do(f func()) {
    // done==0，说明没执行过，进入慢路径
    if atomic.LoadUint32(&o.done) == 0 {
        o.doSlow(f)
    }
}

func (o *Once) doSlow(f func()) {
    o.m.Lock()
    defer o.m.Unlock()
    if o.done == 0 {                       // 双重检查。因为可能有多个协程进入慢路径。第一个协程执行完毕后，后面的协程按顺序还能获取锁，此时再判断一次
        defer atomic.StoreUint32(&o.done, 1) // 执行成功后将 done 变量修改为1
        f()
    }
}
```

在使用该结构体时，我们也需要注意以下的问题：

* [`sync.Once.Do`](https://draveness.me/golang/tree/sync.Once.Do) 方法中传入的函数只会被执行一次，哪怕函数中发生了 `panic`
* 两次调用 [`sync.Once.Do`](https://draveness.me/golang/tree/sync.Once.Do) 方法传入不同的函数只会执行第一次调传入的函数


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wtifs.gitbook.io/diva-notes/go/5.-bing-fa-bian-cheng/24.sync.once-de-shi-xian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
