This is a creation in Article, where the information may have evolved or changed.
10.go Open Source Groupcache Project Toad Note--singleflight
1 singleflight
This package mainly implements a merge operation interface.
1.1 First define a callback function structure call
type call struct {
//
类似
java
的
CountdownLatch
的
wg sync.WaitGroup
//
回调函数
val interface{}
// error
err error
}
1.2 Defining a group structure
Type Group struct {
Musync. Mutex//Protects M
M map[string]*call//lazily initialized
}
Go Use the case of the first letter to determine whether externally visible, uppercase outer visible, lowercase outside is not visible, such as the above Group in the external practical Singleflght The package is accessible, while the Pager can't .
1.3 Do function
The main interface of the package, used to send query requests to other nodes, merging requests for the same key, reducing the potential for hot spots, such as my request for key= "123" data, there are many same key requests when there is no return, and there is no need to post at this time, Just wait for the result to be returned the first time.
Return is a inferace and error. The entry parameter is a key and a function.
func (g *Group) Do(key string, fn func() (interface{}, error)) (interface{}, error) {
//
首先获取
group
锁
g.mu.Lock()
//
映射表不存在就创建
1
个
if g.m == nil {
g.m = make(map[string]*call)
}
//
判断要查询某个
key
的请求是否已经在处理了
if c, ok := g.m[key]; ok {
//
已经在处理了
就释放
group
锁
并
wait
在
wg
上,我们看到
wg
加
1
是在某个时间段内第一次请求时加的
//
并且在完成
fn
操作返回后会
wg done
,那时
wait
等待就会返回,直接返回第一次请求的结果
g.mu.Unlock()
c.wg.Wait()
return c.val, c.err
}
//
如果没有在处理,则创建回调,
wg
加
1
,把回调存到
m
中表示已经有在请求了,释放锁
c := new(call)
c.wg.Add(1)
g.m[key] = c
g.mu.Unlock()
//
执行
fn
,释放
wg
c.val, c.err = fn()
c.wg.Done()
//
加锁将请求从
m
中删除,表示请求已经做好了
g.mu.Lock()
delete(g.m, key)
g.mu.Unlock()
return c.val, c.err
}
2 Singleflight_test
2.1 Testdo
Define a variable G for Group type
Call the Do function. The return value is assigned a value of V.
Determine if V is bar (string)
2.2 Testdoerr
Define a variable G for Group type
Add a custom error as follows:
Someerr: = errors. New ("Someerror")
Then call the Do function. Returns a custom error.
It then determines whether the error returned is correct.
2.3 testdodupsuppress
Define a variable G for Group type
A return function, used with the Detect 10 loop, is also called only once.
fn: = func () (interface{}, error) {
Atomic. AddInt32 (&calls,1)
Return<-c, Nil
}
Defines a constant of 10.
Cycle 10 times
Each WG. ADD (1), then concurrent go func ()
Then wait for 100ms to allow Goroutings to block for a while.
The function returns a channel variable.
Assign a value bar to the channel variable.
2.4 Test Results
Test as follows
= = = RUN Testdo
---pass:testdo (0.00s)
= = = RUN Testdoerr
---pass:testdoerr (0.00s)
= = = RUN testdodupsuppress
---pass:testdodupsuppress (0.10s)
PASS
OK Test 0.227s