3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Go で thread-safe map を作れるかを考える

Last updated at Posted at 2015-05-20

こんにちは。
Go で thread-safe map を作れるか気になりました。複数の goroutine から同一キーへ同時にアクセスがあった場合に正しく queing させる方法でなくてはなりません。lock を最小にしたい場合、工夫が必要です。sync.Mutex を使って考えてみました。

package main

import (
	"sync"
	"fmt"
)

// map 構造(今回の例)
type Key int64
type Value struct {
	e0    []int64
	e1    []float64
	e2    []string
}

// thread-safe map を作れるか?
var cmap   =   map[Key]Value{}  // map 本体(今回は shard 分割していない)
var NUM_SHARD = 1024
var shards = []*sync.Mutex{}
var cmap_m   []map[Key]*sync.Mutex

// e0 の値を put する例
func put_thread_safe (k Key, e0 int64) {
	i := uint64(k)%uint64(NUM_SHARD) // shard id
    shards[i].Lock()  // shard へのアクセスをロック
	if cmap_m[i][k] == nil {
		cmap_m[i][k] = new(sync.Mutex)
	}
	cmap_m[i][k].Lock()  // 他からの cmap へのアクセスは待たせる
    shards[i].Unlock()  // shard へのアクセスのロック解除
	v := cmap[k]  // 値をコピー
	v.e0 = append(v.e0, e0)  // 値を操作する例
	cmap[k] = v  // 書き戻す
	cmap_m[i][k].Unlock()  // 他からのアクセスのロック解除
}

func init_shard() {
    for i := 0; i < NUM_SHARD; i++ {
		shards = append(shards, new(sync.Mutex))
		cmap_m = append(cmap_m, map[Key]*sync.Mutex{})
	}
}

func main () {
	init_shard()
	x := make(map[Key][]int64)
	x[37] = []int64{2, 4}
	x[89] = []int64{2, 3, 5, 7}
    for _, k := range []Key{37, 89} {
		for _, e0 := range x[k] {
			put_thread_safe(k, e0)
		}
    }
	fmt.Println(cmap)  // ==> map[37:{[2 4] [] []} 89:{[2 3 5 7] [] []}]
}
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?