go言語における並行処理のセキュリティとロックの説明
この記事を読んで、ロックについての理解を深めることから始めるとよいでしょう。
GO並行プログラミングにおける相互排除ロックと読み取り/書き込みロック
Mutex - 相互排除ロック
Mutexは、主にCAS命令+スピン+セマフォで実装されています。
データ構造
var='LotArea'
data=pd.concat(df_train['SalePrice'],df_train[var],axis=1)
data.plot.scatter(x=var,y='SalePrice',ylim=(0,800000))
上記の2つの構造体は、合わせても8バイトのスペースしか取らず、Go言語では相互に排他的なロックを表します。
状態です。
デフォルトでは、相互排他的ロックのすべてのステータスビットは0である。
var='LotArea'
data=pd.concat([df_train['SalePrice'],df_train[var]],axis=1)
data.plot.scatter(x=var,y='SalePrice',ylim=(0,800000))
の異なるビットは
- 1ビットはロックされているかどうかを示す
- 1ビットは、同時進行中のプロセスが起動されたかどうかを示す
- 1ビットで飢餓状態であるかどうかを示す
-
残りの29ビットは、ブロッキングしているコプロセスの数を示す
通常モードと飢餓モード
通常モード:すべてのゴルーチンがFIFO順にロック獲得を行い、起動中のゴルーチンと新しく要求されたゴルーチンが同時にロック獲得を行い、通常新しく要求されたゴルーチンがロックを獲得しやすく(CPUを連続的に占有)、起動中のゴルーチンがロックを獲得しやすいわけではありません。
飢餓モード:ロックを取得しようとするすべてのゴルーチンが並んで待ち、ロックを要求する新しいゴルーチンはロック取得を行わず(スピンを無効にして)、ロック取得を待つキューの末尾に参加します。
ゴルーチンが相互排他的ロックを取得し、それがキューの最後であるか、1ms未満の待ち時間であれば、現在の相互排他的ロックは通常モードに切り替わります。
通常モードのミューテックスは、スターベーションモードよりも性能が良く、Goroutine がロックの取得待ちで立ち往生することによる高いテールレイテンシを回避することができます。
ミューテックスロックのロック処理
- ロックが初期状態の場合、直接ロックされる
- ミューテックスロックがロック状態にあり、通常モードで動作している場合、goroutineはスピンに入り、ロックが解放されるのを待ちます。
ゴルーチンがスピンに入るための条件は、次のように非常に厳しいものです。
- インターロックは、通常モードでのみスピンに入ることができます。
runtime.sync_runtime_canSpin
真を返す必要があるマルチCPUのマシンで動作している。
現在のGoroutineがそのロックを取得するためにスピンに入る回数が4回未満である。
現在のマシンに少なくとも1つの実行プロセッサPがあり、処理のための実行キューが空である。
- 現在のGoroutineがロックのために1ms以上待つと、ミューテックスロックはスターベーションモードに切り替わります。
-
通常の条件下ではミューテックスロックは通過する
runtime.sync_runtime_SemacquireMutex
ロックを取得しようとする Goroutine を休止状態に切り替え、ロック保持者が目を覚ますのを待ちます。 - 現在の Goroutine が Mutex 上で最後に待機している同時接続であるか、1ms 未満であれば、 Mutex を通常モードに切り替えます。
ミューテックスロックを解除する処理
相互排他的ロックが既に解除されている場合、再度ロックを解除すると例外が発生する
ミューテックスロックがスターベーションモードになり、待ち行列の先頭のGoroutineにロックの所有権を与える場合
は、ロック解放を待っている Goroutine がない場合、あるいは、すでに起きている Goroutine がロックを獲得している場合は直接戻り、それ以外の場合は、対応する Goroutine を起こして 戻ります。
ミューテックスロックの使用は、2つ以上のGoroutinesでロックされ、ロック解除されることはありませんグローバルに同じミューテックスを使用していないビジネスを記述することをお勧めしますミューテックスは(関数のパラメータを介して渡されない含む)コピーされてはならない、それ以外の場合は参照を渡す前にロックの状態をコピーします。これは、デッドロックを生成するのは簡単ですが、キーは、コンパイラがこのデッドロックを見つけることができないことです。
RWMutex - リード/ライトロック
Go の RWMutex は書き込み優先の設計を使用しています。
データ構造
type RWMutex struct {
w Mutex // multiplex the capabilities provided by the mutex lock
writerSem uint32 //writer semaphore
readerSem uint32 //reader semaphore
readerCount int32 // stores the number of read operations currently being performed
readerWait int32 // indicates the number of read operations waiting to complete when a write operation blocks
}
書き込みロック
書き込みロックを取得します。
- ロックは、構造体が保持するMutex構造体のMutex.Lockを呼び出すことで、以降の書き込み操作をブロックします。
-
ロックする
readerCount
を2^30で負数にし、その後の読み込み操作をブロックする。 -
他のGoroutineがリードロックを保持している場合、そのGoroutineはすべてのリードロックが実行され解放されるまでスリープ状態になる
writerSem
セマフォは現在のワーカーを目覚めさせる
書き込みロックを解除する。
-
を解放します。
readerCount
を正の数に戻し、読み取りロックを解除します。 - リードロックでスリープしているGoroutineをすべてウェイクアップさせる
- Mutex.Unlockを呼び出して書き込みロックを解除する。
書き込みロックを取得すると、読み取りロックを取得する前に書き込みロックの取得をブロックします。これは、連続した書き込み操作によって読み取り操作が「飢餓」に陥らないようにするための戦略です。
読み取りロック
リードロックの取得
リードロックを取得するための方法
sync.RWMutex.RLock
簡単に言うと、このメソッドは
readerCount
に1を加えたものです。
- このメソッドが負の数を返した場合(他のゴルーチンが書き込みロックを取得したことを表し、現在のゴルーチンはロックが解放されるのを待つためにスリープ状態になります)。
- もしこのメソッドが負でない数字を返した場合、つまりどのゴルーチンも書き込みロックを取得していない場合、このメソッドは成功裏に
読み取りロックを解除する
リードロックの解除方法
sync.RWMutex.RUnlock
このメソッドでは
-
意志
readerCount
をマイナスして、戻り値に応じて別途処理されます。 - 戻り値が0以上の場合、読み取りロックは直接解除される
-
0より小さい場合は、書き込み操作が行われていることを意味します。
sync.RWMutex.rUnlockSlow
そうすればreaderWait
を1つ減らし、すべての読み取り操作が解放されたときにセマフォをトリガーします。writerSem
このセマフォがトリガーされると、スケジューラは書き込みロックを取得しようとするGoroutineを起動します。
待機グループ
sync.WaitGroup
Goroutineのグループのリターンを待つことができます。
sync.WaitGroup
3つのメソッドが外部に公開されている。
<テーブル メソッド名 機能 (wg * WaitGroup) Add(delta int) カウンタ+デルタ (wg *WaitGroup) Done() カウンタ-マイナス1 (wg *WaitGroup) Wait() カウンタが0になるまでブロック
sync.WaitGroup.Done
のペアに過ぎない。
sync.WaitGroup.Add
メソッドの単純なラッパーであり、add -1
Sync.Map
Go言語の組み込みマップは、コンカレンシーセーフではありません。
Go言語の
sync
パッケージは、マップのコンカレンシーセーフバージョンをすぐに利用できるようにします。
sync.Map
. 相互排他的ロックを用いた並行性セキュリティ
データ構造
type Map struct {
mu Mutex
read atomic.Value // readOnly
dirty map[interface{}]*entry
misses int
}
Out-of-the-box とは、内蔵マップのように make 関数で初期化することなく、そのまま使えるという意味です。また
sync.Map
メソッドが組み込まれています。
<テーブル メソッド名 機能 (m *sync.Map)Store(key, value interface{}) キーと値のペアを保存する (m *sync.Map)Load(key interface{}) キーを元に対応する値を取得する (m *sync.Map)Delete(key interface{}) キーと値のペアを削除する (m *sync.Map)Range(f func(key, value interface{}) bool) sync.Mapを繰り返し処理します。Rangeの引数は関数 *sync.mapはLen()メソッドを持っていません。
アトミック操作(アトミックパッケージ)
コード中のロック操作は、カーネル状態でのコンテキスト・スイッチングを伴うため、時間とコストがかかることがあります。基本的なデータ型では、同時実行安全性のためにアトミック操作を使用することもできます。アトミック操作はユーザー ステートで実行できる方法で Go 言語が提供しているので、組み込み標準ライブラリ sync/atomic が提供しているロック操作よりも性能が良いからです。
参考にしてください。
Goの並行プログラミング、同期プリミティブとロック|Go言語の設計と実装(draveness.me)
今回の記事は、go言語における並行処理のセキュリティとロックについてです。go言語における並行処理のセキュリティとロックについての詳しい情報は、Script Houseの過去の記事を検索するか、以下の関連記事を引き続きご覧ください。
関連
-
Go言語の基本型と定数の使用例詳細
-
囲碁言語の基本構造と使用例
-
囲碁言語基本囲碁インターフェイス使用例詳細
-
Go言語 netパッケージ RPCリモートコール 3つの方法 httpとjson-rpcとtcp
-
golangはファイルをダウンロードするためにマルチプロセッシングを実装しています(ブレークポイント転送をサポート)。
-
Goはsync.Mapを使って、mapの同時操作問題を解決している
-
Go言語における20個のプレースホルダーのリスト
-
Go言語並行プログラミングのための相互排除ロックMutexと読み取り/書き込みロックRWMutex
-
囲碁がGC問題の引き金になる場合の話
-
go 言語のデバッグ: exec: "gcc": 実行可能ファイルが %PATH% に見つからない
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン