深さ解析Onceソース
3478 ワード
目次
https://mp.weixin.qq.com/s/b89PmljELaPaVuLw-YIQKg
syncとは何ですか。Once
Onceは、1回の動作のみを実行するために使用することができ、通常、単一のオブジェクトの初期化シーンに使用される.
Onceは、単一のリソースを初期化したり、一度だけ共有リソースを初期化したり、テスト時にテストリソースを初期化したりするために同時アクセスするためによく使用されます.
sync.Onceは1つのメソッドDoのみを暴露し、Doメソッドを複数回呼び出すことができますが、最初にDoメソッドを呼び出すとfパラメータが実行されます.ここでfはパラメータなしで戻り値のない関数です.
syncの使用方法Once
私が担当しているプロジェクトの1つについて言えば、プロジェクトの構成はサードパーティのプラットフォームに掛けられているので、プロジェクトの起動時にリソースの構成を取得する必要があります.構成が1回しか取得できないことを保証する方法が必要ですので、syncを使用することを考えています.Onceでリソースを取得します.これにより、一度だけ実行されるリソース取得メソッドを他の場所で呼び出すことを防止することができる.
次は簡単にDemoを書いてsyncを実証します.Onceの使い方package main
import (
"fmt"
"sync"
)
var once sync.Once
var con string
func main() {
once.Do(func() {
con = "hello Test once.Do"
})
fmt.Println(con)
}
コードの説明:
コードは比較的簡単で、Doメソッドを呼び出すことによって、閉パッケージ方式を採用し、文字列(「hello Test once.Do」)をconに付与し、さらに値を印刷するsyncである.Onceの使用は、比較的使いやすいです.
しかし、私たちが一つの方法やフレームワークを使うとき、それを手のひらのように知らなければ、いつも頼りにならないので、心が落ち着かないような気がします.そのためにsyncについてお話ししましょうOnceのソースコードが実現し、彼を逃げ場がない.
ソース分析
次にsyncを分析します.Doはどのように実現され、パッケージsyncの下に保存されていますか.goファイルでは、ソースコードは次のとおりです.// sync/once.go
type Once struct {
done uint32 // 0 ,1
m Mutex
}
func (o *Once) Do(f func()) {
// done 0, 0, , doSlow()
if atomic.LoadUint32(&o.done) == 0 {
// Outlined slow-path to allow inlining of the fast-path.
o.doSlow(f)
}
}
//
func (o *Once) doSlow(f func()) {
o.m.Lock()
defer o.m.Unlock()
// done
if o.done == 0 {
// f() , done 1
defer atomic.StoreUint32(&o.done, 1)
// f()
f()
}
}
次は二つの部分に分けて分析します.第一部分はOnceの構造体構成構造で、第二部分はDo関数の実現原理で、私はコードに注釈をつけて、心を込めて読んでから収穫があることを保証します.
こうぞうたい
type Once struct {
done uint32 // 0 ,1
m Mutex
}
まずstruct構造体Onceを定義し、doneとmの2つのメンバー変数を格納します.
doneメンバー変数
私が担当しているプロジェクトの1つについて言えば、プロジェクトの構成はサードパーティのプラットフォームに掛けられているので、プロジェクトの起動時にリソースの構成を取得する必要があります.構成が1回しか取得できないことを保証する方法が必要ですので、syncを使用することを考えています.Onceでリソースを取得します.これにより、一度だけ実行されるリソース取得メソッドを他の場所で呼び出すことを防止することができる.
次は簡単にDemoを書いてsyncを実証します.Onceの使い方
package main
import (
"fmt"
"sync"
)
var once sync.Once
var con string
func main() {
once.Do(func() {
con = "hello Test once.Do"
})
fmt.Println(con)
}
コードの説明:
コードは比較的簡単で、Doメソッドを呼び出すことによって、閉パッケージ方式を採用し、文字列(「hello Test once.Do」)をconに付与し、さらに値を印刷するsyncである.Onceの使用は、比較的使いやすいです.
しかし、私たちが一つの方法やフレームワークを使うとき、それを手のひらのように知らなければ、いつも頼りにならないので、心が落ち着かないような気がします.そのためにsyncについてお話ししましょうOnceのソースコードが実現し、彼を逃げ場がない.
ソース分析
次にsyncを分析します.Doはどのように実現され、パッケージsyncの下に保存されていますか.goファイルでは、ソースコードは次のとおりです.// sync/once.go
type Once struct {
done uint32 // 0 ,1
m Mutex
}
func (o *Once) Do(f func()) {
// done 0, 0, , doSlow()
if atomic.LoadUint32(&o.done) == 0 {
// Outlined slow-path to allow inlining of the fast-path.
o.doSlow(f)
}
}
//
func (o *Once) doSlow(f func()) {
o.m.Lock()
defer o.m.Unlock()
// done
if o.done == 0 {
// f() , done 1
defer atomic.StoreUint32(&o.done, 1)
// f()
f()
}
}
次は二つの部分に分けて分析します.第一部分はOnceの構造体構成構造で、第二部分はDo関数の実現原理で、私はコードに注釈をつけて、心を込めて読んでから収穫があることを保証します.
こうぞうたい
type Once struct {
done uint32 // 0 ,1
m Mutex
}
まずstruct構造体Onceを定義し、doneとmの2つのメンバー変数を格納します.
doneメンバー変数
// sync/once.go
type Once struct {
done uint32 // 0 ,1
m Mutex
}
func (o *Once) Do(f func()) {
// done 0, 0, , doSlow()
if atomic.LoadUint32(&o.done) == 0 {
// Outlined slow-path to allow inlining of the fast-path.
o.doSlow(f)
}
}
//
func (o *Once) doSlow(f func()) {
o.m.Lock()
defer o.m.Unlock()
// done
if o.done == 0 {
// f() , done 1
defer atomic.StoreUint32(&o.done, 1)
// f()
f()
}
}
type Once struct {
done uint32 // 0 ,1
m Mutex
}
mメンバー変数
Do
func (o *Once) Do(f func()) {
// done 0, 0, , doSlow()
if atomic.LoadUint32(&o.done) == 0 {
// Outlined slow-path to allow inlining of the fast-path.
o.doSlow(f)
}
}
//
func (o *Once) doSlow(f func()) {
o.m.Lock()
defer o.m.Unlock()
// done
if o.done == 0 {
// f() , done 1
defer atomic.StoreUint32(&o.done, 1)
// f()
f()
}
Do関数を呼び出すと、まずdone値が0であるかどうかを判断し、1であれば、入力された匿名関数f()が実行されたことを示し、再実行する必要はない.0であれば、入力された匿名関数f()がまだ実行されていないことを示すdoSlow()関数を呼び出して初期化する.
doSlow()関数では、同時goroutineがこの関数に入ると、f()匿名関数を実行するgoroutineが1つしかないことを保証します.このため,反発ロックを加えて1つのgoroutineのみを初期化することを保証するとともに,ダブルチェックのメカニズム(double-checking)を採用し,o.doneが0であるか否かを再判断し,0であれば初めて実行し,実行が完了するとo.doneを1に設定してロックを解放する必要がある.
このとき複数のgoroutineが同時にdoSlowメソッドに入ったとしても、ダブルチェックのメカニズムのため、後続のgoroutineはo.doneの値が1であることを見て、fを再実行することはありません.
これにより、同時goroutineがfの完了を待つことが保証され、fが複数回実行されないことが保証される.
文章も更新され続け、微信で「マイモcoding」を検索して最初に読むことができます.毎日良質な文章、大工場の経験、大工場の経験を分かち合い、面接を支援することは、プログラマー一人一人が注目すべきプラットフォームである.