最近、コードを取得するデータの一部を見て、シングルフライトの使用を参照してください、コードは非常に短いですが、キャッシュヒットを防ぐために、簡単なレコードのケースを達成するために役立つことができます。
キャッシュヒット対策
開発現場では、あるインターフェースへのアクセス数が急激に増加し、レスポンスの遅延やサービスのダウンタイムが発生することがあります。一般的な操作は、データベース操作への高度な同時アクセスを防ぐために、通常はいくつかのキャッシュ操作を追加して、データベースへの圧力を緩和することです。 しかし、いくつかの異常な状況、たとえば、キャッシュの無効化と再フェッチの過程で、同じ時点で同じデータにアクセスするための多くの同時要求があり、この時点で、キャッシュがリフレッシュされていないため、データベースへのアクセス要求が多くなり、データベースへの過度の圧力につながります。 Singleflightは、同じリクエストを集約し、あるリクエストが既に行われていることが判明した場合、他のデータアクセスを保留し、あるリクエストが戻ってくるのを待ち、それらを統一的に返します。
具体的なコード解析
結果を直接返すDoと、統計情報を返すDoChanの2つのインターフェイスが外部に提供されています。
func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) { g.mu.Lock() if g.m == nil { g.m = make(map[string]*call) } if c, ok := g.m[key]; ok { c.dups++ g.mu.Unlock() c.wg.Wait() return c.val, c.err, true } c := new(call) c.wg.Add(1) g.m[key] = c g.mu.Unlock() g.doCall(c, key, fn) return c.val, c.err, c.dups > 0}
func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result { ch := make(chan Result, 1) g.mu.Lock() if g.m == nil { g.m = make(map[string]*call) } if c, ok := g.m[key]; ok { c.dups++ c.chans = append(c.chans, ch) g.mu.Unlock() return ch } c := &call{chans: []chan<- Result{ch}} c.wg.Add(1) g.m[key] = c g.mu.Unlock() go g.doCall(c, key, fn) return ch}
Doインターフェイスを例にとってみましょう。
まずmutextのロックを使って、コードに同期の問題がないことを確認してください。
if c, ok := g.m[key]; ok { //すでに実行されたコードがあるかどうかを判断する
すでに1つある場合は、sync.WaitGroupのwaitメソッドでホールドロジックが実行され、最初の実行ロジックがOKになるのを待ち、対応する値を返します。
そうでない場合は、呼び出し構造体が作成され、sync.WaitGroup メソッドが対応する Add 操作を実行し、操作のキーをマップに追加します。ロックを解除し、適切な関数を実行します。
doCallアプローチについて:
func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) { c.val, c.err = fn() c.wg.Done() g.mu.Lock() delete(g.m, key) for _, ch := range c.chans { ch <- Result{c.val, c.err, c.dups > 0} } g.mu.Unlock()}
doCallは、入力された関数を実行し、各アクセスロジックに対して生成されたチャン ネルを繰り返し処理し、チャンンを介して統計情報を返します。
一言:
singleflight全体的にコードの100行以上、比較的明確な問題を解決するために、非常に短く、簡潔です。戻り値については、最初の方法は、直接結果を返す、これは非常に明確です。2番目の方法は、ちゃんぽん方法を返すことであり、いくつかのパラメータを渡します。 以前は、iOSのコードを書くときは、非同期リターンのために、一般的にブロックを渡すと、非同期コールバック、またはデカップリングする方法の通知を介してブロックを介して終了します。 今回は非同期同期のもう一つの方法があるでしょう、多分我々はそれから学ぶことができる、それは非常に良いです。





