// Copyright 2013 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.
// Package singleflight provides a duplicate function call suppression// mechanism.
package singleflightimport// call is an in-flight or completed singleflight.Do calltypecallstruct {wgsync.WaitGroup// These fields are written once before the WaitGroup is done // and are only read after the WaitGroup is done.valanyerrerror// These fields are read and written with the singleflight // mutex held before the WaitGroup is done, and are read but // not written after the WaitGroup is done.dupsintchans []chan<- Result}// Group represents a class of work and forms a namespace in// which units of work can be executed with duplicate suppression.typeGroupstruct {musync.Mutex// protects mmmap[string]*call// lazily initialized}// Result holds the results of Do, so they can be passed// on a channel.typeResultstruct {ValanyErrerrorSharedbool}// Do executes and returns the results of the given function, making// sure that only one execution is in-flight for a given key at a// time. If a duplicate comes in, the duplicate caller waits for the// original to complete and receives the same results.// The return value shared indicates whether v was given to multiple callers.func ( *Group) ( string, func() (any, error)) ( any, error, bool) { .mu.Lock()if .m == nil { .m = make(map[string]*call) }if , := .m[]; { .dups++ .mu.Unlock() .wg.Wait()return .val, .err, true } := new(call) .wg.Add(1) .m[] = .mu.Unlock() .doCall(, , )return .val, .err, .dups > 0}// DoChan is like Do but returns a channel that will receive the// results when they are ready.func ( *Group) ( string, func() (any, error)) <-chanResult { := make(chanResult, 1) .mu.Lock()if .m == nil { .m = make(map[string]*call) }if , := .m[]; { .dups++ .chans = append(.chans, ) .mu.Unlock()return } := &call{chans: []chan<- Result{}} .wg.Add(1) .m[] = .mu.Unlock()go .doCall(, , )return}// doCall handles the single call for a key.func ( *Group) ( *call, string, func() (any, error)) { .val, .err = () .mu.Lock() .wg.Done()if .m[] == {delete(.m, ) }for , := range .chans { <- Result{.val, .err, .dups > 0} } .mu.Unlock()}// ForgetUnshared tells the singleflight to forget about a key if it is not// shared with any other goroutines. Future calls to Do for a forgotten key// will call the function rather than waiting for an earlier call to complete.// Returns whether the key was forgotten or unknown--that is, whether no// other goroutines are waiting for the result.func ( *Group) ( string) bool { .mu.Lock()defer .mu.Unlock() , := .m[]if ! {returntrue }if .dups == 0 {delete(.m, )returntrue }returnfalse}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.