# GO Sync.Once 使用


sync.Once 用于确保某个函数只执行一次，无论有多少个 goroutine 尝试执行它。它有一个方法 Do(f func())，传入需要执行的函数。

基本用法示例：

```go
package main

import (
    "fmt"
    "sync"
)

func main() {
    var once sync.Once
    done := make(chan bool)

    // 模拟多个 goroutine 调用
    for i := 0; i < 10; i++ {
        go func(x int) {
            // once.Do() 传入的函数只会执行一次
            once.Do(func() {
                fmt.Printf("只执行一次: %d\n", x)
            })
            // 这行每个 goroutine 都会执行
            fmt.Printf("goroutine %d 完成\n", x)
            done <- true
        }(i)
    }

    // 等待所有 goroutine 完成
    for i := 0; i < 10; i++ {
        <-done
    }
}
```

常见使用场景：

1. 单例模式：

   ```go
   type Singleton struct{}

   var (
       instance *Singleton
       once     sync.Once
   )

   func GetInstance() *Singleton {
       once.Do(func() {
           instance = &Singleton{}
       })
       return instance
   }
   ```

2. 一次性初始化：

   ```go
   type Config struct {
       settings map[string]string
       once     sync.Once
   }

   func (c *Config) Load() {
       c.once.Do(func() {
           // 加载配置的代码
           c.settings = make(map[string]string)
           c.settings["key"] = "value"
       })
   }
   ```

3. 延迟关闭资源：

   ```go
   type Connection struct {
       once sync.Once
       quit chan struct{}
   }

   func (c *Connection) Close() {
       c.once.Do(func() {
           close(c.quit)
       })
   }
   ```

4. 错误处理：

   ```go
   type ErrorHandler struct {
       once  sync.Once
       err   error
   }

   func (e *ErrorHandler) HandleError(err error) {
       e.once.Do(func() {
           e.err = err
           // 只处理第一个错误
           fmt.Println("处理错误:", err)
       })
   }
   ```

sync.Once 的特点：

1. 线程安全：可以在多个 goroutine 中安全使用
2. 只执行一次：无论调用多少次，传入的函数只会执行一次
3. 所有 goroutine 都会等待第一次执行完成
4. 执行失败不会重试：如果函数执行出错，后续调用也不会重新执行
5. 不能重置：一旦执行过，就不能重新开始

sync.Once 的 Do 方法只保证函数执行一次，但不保证是哪个 goroutine 执行的。如果有多个 goroutine 同时调用，只有一个会执行函数，其他的会等待执行完成。


---

> 作者: Nite  
> URL: https://www.nite07.com/zh-cn/posts/go-sync-once/  

