ホームページ > バックエンド開発 > Golang > Go は明示的な同期を行わずにどのようにしてスレッド セーフを実現するのでしょうか?

Go は明示的な同期を行わずにどのようにしてスレッド セーフを実現するのでしょうか?

Barbara Streisand
リリース: 2024-12-18 10:30:10
オリジナル
361 人が閲覧しました

How Does Go Achieve Thread Safety Without Explicit Synchronization?

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:

  • sync.RWMutex を使用して、それぞれをブロックせずに同時読み取りを許可します。その他。
  • エラーやパニックが発生した場合でもミューテックスが確実に解放されるように、ロック解除の遅延を導入します。
  • カプセル化して使いやすくするために、ミューテックスと保護されたデータを構造体内に埋め込みます。

改良された実装は次のようになります。 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 ブログ: コミュニケーションによるメモリの共有](リンク)
  • [別のスレッドからの値の読み取り](リンク)

以上がGo は明示的な同期を行わずにどのようにしてスレッド セーフを実現するのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート