Go のスレッド セーフ: 同期の代替手段
プログラミングの領域では、スレッド セーフにより、変数に同時にアクセスできることが保証されます。データの不整合を引き起こすことなく複数のスレッドを実行できます。 Go では、Java の synchronized キーワードに見られるように、同期の概念は明示的に強制されるのではなく、さまざまなメカニズムを通じて対処されます。
Go は、「メモリを共有する」のではなく「共有することによって通信する」というアプローチを提唱しています。コミュニケーションを取っている。」このパラダイムは、共有変数に直接アクセスするのではなく、チャネルを介してゴルーチン間で情報を交換することを奨励します。
Mutex: 古典的なソリューション
ただし、変数のロックと共有が困難なシナリオでは、必然的に、Go はミューテックスを提供します。次の例を考えてみましょう。
import ( "sync" ) var ( mu sync.Mutex protectMe int ) func getMe() int { mu.Lock() me := protectMe mu.Unlock() return me } func setMe(me int) { mu.Lock() protectMe = me mu.Unlock() }
このコードでは、変数protectMeは、muという名前のミューテックスを使用して保護されています。 getMe 関数と setMe 関数は、このミューテックスを利用して、protectMe への安全な同時アクセスを保証します。
改善点と代替案
上記のソリューションは機能しますが、機能を強化する方法がいくつかあります。 it:
改良された実装は次のようになります。 this:
type Me struct { sync.RWMutex me int } func (m *Me) Get() int { m.RLock() defer m.RUnlock() return m.me } func (m *Me) Set(me int) { m.Lock() m.me = me m.Unlock() } var me = &Me{}
アトミック操作
単一の整数を保護するために、Go は sync/atomic パッケージを通じてアトミック操作を提供します。次のコードを考えてみましょう。
import "sync/atomic" var protectMe int32 func getMe() int32 { return atomic.LoadInt32(&protectMe) } func setMe(me int32) { atomic.StoreInt32(&protectMe, me) }
アトミック操作は単一値へのスレッドセーフなアクセスを保証し、特定の状況ではミューテックスよりも優れたパフォーマンスを提供する可能性があります。
共有による通信
前述したように、Go ではチャネルを介したコミュニケーションが推奨されています。 2 つのゴルーチンがあると想像してください。1 つは状態を設定し、もう 1 つは状態を読み取ります。共有変数を使用してその変数へのアクセスを同期する代わりに、チャネルを使用してセッターからリーダーに状態を送信できます。
import "sync" var c chan int func init() { c = make(chan int) } func getMe() int { return <-c } func setMe(me int) { c <- me }
このアプローチでは、共有変数と同期の必要性がなくなり、コードを作成し、同時アクセスに対して本質的に安全にしています。
追加リソース
以上がGo は明示的な同期を行わずにどのようにしてスレッド セーフを実現するのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。