├── .gitignore ├── LICENSE ├── README.md ├── go.mod ├── go.sum └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 go-demo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # singleflight-demo 2 | singleflight包原理解析 3 | 4 | 5 | ## 执行 6 | `go run main.go` 7 | 8 | ### 结果输出 9 | 10 | ``` 11 | 2020/03/08 17:18:16 get key from database 12 | 2020/03/08 17:18:16 data 13 | 2020/03/08 17:18:16 data 14 | 2020/03/08 17:18:16 data 15 | 2020/03/08 17:18:16 data 16 | 2020/03/08 17:18:16 data 17 | 2020/03/08 17:18:16 data 18 | 2020/03/08 17:18:16 data 19 | 2020/03/08 17:18:16 data 20 | 2020/03/08 17:18:16 data 21 | 2020/03/08 17:18:16 data 22 | ``` 23 | ## 原理分析 24 | 25 | [https://silenceper.com/blog/202003/singleflight/](https://silenceper.com/blog/202003/singleflight/) 26 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-demo/singleflight-demo 2 | 3 | go 1.13 4 | 5 | require golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= 2 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 3 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "log" 6 | "sync" 7 | 8 | "golang.org/x/sync/singleflight" 9 | ) 10 | 11 | var errorNotExist = errors.New("not exist") 12 | var g singleflight.Group 13 | 14 | func main() { 15 | var wg sync.WaitGroup 16 | wg.Add(10) 17 | 18 | //模拟10个并发 19 | for i := 0; i < 10; i++ { 20 | go func() { 21 | defer wg.Done() 22 | data, err := getData("key") 23 | if err != nil { 24 | log.Print(err) 25 | return 26 | } 27 | log.Println(data) 28 | }() 29 | } 30 | wg.Wait() 31 | } 32 | 33 | //获取数据 34 | func getData(key string) (string, error) { 35 | data, err := getDataFromCache(key) 36 | if err == errorNotExist { 37 | //模拟从db中获取数据 38 | v, err, _ := g.Do(key, func() (interface{}, error) { 39 | return getDataFromDB(key) 40 | //set cache 41 | }) 42 | if err != nil { 43 | log.Println(err) 44 | return "", err 45 | } 46 | 47 | //TOOD: set cache 48 | data = v.(string) 49 | } else if err != nil { 50 | return "", err 51 | } 52 | return data, nil 53 | } 54 | 55 | //模拟从cache中获取值,cache中无该值 56 | func getDataFromCache(key string) (string, error) { 57 | return "", errorNotExist 58 | } 59 | 60 | //模拟从数据库中获取值 61 | func getDataFromDB(key string) (string, error) { 62 | log.Printf("get %s from database", key) 63 | return "data", nil 64 | } 65 | --------------------------------------------------------------------------------