同時条件でマップの読み取りと書き込みを行うときに発生する問題を見てみましょう。コードは次のとおりです。
// intからintへのマップを作成します
m := make(map[int]int)
// 並行処理を開始します
go func() {
// マップに書き込みを繰り返します
for {
m[1] = 1
}
}()
// 並行処理を開始します
go func() {
// マップを繰り返し読み取ります
for {
_ = m[1]
}
}()
// 無限ループで、バックグラウンドで並行プログラムを実行します
for {
}
コードを実行するとエラーが報告され、出力は次のようになります。
fatal error: concurrent map read and map write
エラー メッセージは、マップの読み取りとマップの書き込みが同時に行われたこと、つまり 2 つの同時関数がマップの読み取りと書き込みを継続的に使用され、競合状態が発生したことを示しています。マップはこの同時操作を内部でチェックし、事前に検出します。
同時読み取りと書き込みが必要な場合、一般的な方法はロックを追加することですが、パフォーマンスは高くありません。バージョン 1.9 では、Go 言語はより効率的で同時並行的に安全な sync.Map を提供します。map とは異なり、sync.Map はベースではありません。 on 言語のネイティブ形式で提供されますが、同期パッケージの下の特別な構造になります。
sync.Map には次のプロパティがあります。
- 初期化する必要はなく、直接宣言するだけです。
- sync.Mapはmapのメソッドを使って値の取得や設定などの操作を行うことはできませんが、sync.Mapのメソッドを使って呼び出します。Storeは保存、Loadは取得、Deleteは削除を意味します。
- トラバーサル操作を実行するには、コールバック関数で Range を使用します。コールバック関数は、内部でトラバースされた値を返します。Range パラメータのコールバック関数の戻り値は、反復トラバーサルを続行する必要がある場合は true を返し、反復トラバーサルが終了する場合は false を返します。
同時安全な sync.Map のデモ コードは次のとおりです。
package main
import (
"fmt"
"sync"
)
func main(){
var scene sync.Map
// キーとバリューをsync.Mapに保存
scene.Store("greece", 97)
scene.Store("london", 100)
scene.Store("egypt", 200)
// キーを元にsync.Mapからバリューを取得
fmt.Println(scene.Load("london"))
// キーに基づいて対応するキー値のペアを削除する
scene.Delete("london")
// すべてのsync.Mapのキーとバリューを繰り返し処理
scene.Range(func(k, v interface{}) bool {
fmt.Println("iterate:", k, v)
return true
})
}
コード出力は次のとおりです。
100 true
iterate: egypt 200
iterate: greece 97
コードの説明は次のとおりです。
- 10 行目ではシーンを宣言しており、そのタイプは sync.Map ですが、sync.Map は make では作成できないことに注意してください。
- 13 行目から 15 行目では、一連のキーと値のペアを sync.Map に保存し、sync.Map はキーと値をインターフェース タイプに保存します。{}
- 18行目、sync.Mapのキーをscene.Load()メソッドに渡し、キーに対応する値を返します。
- 21 行目では、sync.Map の削除で、指定されたキーを使用して、対応するキーと値のペアを削除できます。
- 24 行目では、Range() メソッドは sync.Map を走査することができ、走査のために匿名関数を提供する必要があります。パラメータは k と v で、型はinterface{}です。Range() が要素を走査するたびに、この匿名関数を呼び出して、結果が返されます。
sync.Map はマップの数を取得するメソッドを提供しません。代わりに、sync.Map を取得するときに独自に数をトラバースして計算することです。sync.Map は同時実行の安全性を確保するためにある程度のパフォーマンスの損失があります。 – 同時実行の状況では、同期を使用するよりもマップを使用する方が優れています。マップの方がパフォーマンスが向上します。