Slide 1

Slide 1 text

© DMM © DMM CONFIDENTIAL sync/v2 プロポーザルの 背景と sync.Pool について DMM.go #10 24新卒 松本響輝(matumoto) 2025-05-15

Slide 2

Slide 2 text

© DMM 2 松本 響輝 (matumoto) ● 合同会社DMM.com 開発統括本部マーケティングテクノロジー 部開発チーム ● Goがちょっと好きな24新卒です ● X: @matumoto_1234

Slide 3

Slide 3 text

© DMM 発表の目的 • sync/v2 についてちょっと詳しくなる • 今後注目される機能に目を向ける足がかりになれれば! • 追加される機能の背景や議論を知ってもっとGoを好きに! • Approveされていない のであくまで参考程度に 3

Slide 4

Slide 4 text

© DMM 目次 • v2のプロポーザル一覧 • syncパッケージ(v1)のおさらい • インターフェースのメモリ割り当てについて • sync/v2パッケージのプロポーザル • ジェネリクス対応とv2 • まとめ 4

Slide 5

Slide 5 text

© DMM CONFIDENTAL v2のプロポーザル一覧

Slide 6

Slide 6 text

© DMM 6 label:v2 かつ label:Proposal なものは32件もある

Slide 7

Slide 7 text

© DMM 7 今回、sync/v2 について紹介

Slide 8

Slide 8 text

© DMM CONFIDENTAL そのまえに

Slide 9

Slide 9 text

© DMM CONFIDENTAL syncパッケージ (v1)のおさらい

Slide 10

Slide 10 text

© DMM Go1.24までの sync パッケージの機能 ● 代表的なもの ○ sync.Pool ○ sync.Map ○ sync.WaitGroup ○ sync.Mutex ○ … 10

Slide 11

Slide 11 text

© DMM それぞれの概要 ● 代表的なもの ○ sync.Pool → スレッドセーフなキャッシュ(GCの負荷を軽減) ○ sync.Map → スレッドセーフなmap ○ sync.WaitGroup → goroutine の待機に ○ sync.Mutex → 排他制御に ○ … 11

Slide 12

Slide 12 text

© DMM 今回 sync.Pool と sync.Map に注目 ● 代表的なもの ○ sync.Pool → スレッドセーフなキャッシュ(GCの負荷を軽減) ○ sync.Map → スレッドセーフなmap ○ sync.WaitGroup → goroutine の待機に ○ sync.Mutex → 排他制御に ○ … 12

Slide 13

Slide 13 text

© DMM sync.Pool 型 13

Slide 14

Slide 14 text

© DMM sync.Pool 型 14 any を返す関数を渡す

Slide 15

Slide 15 text

© DMM sync.Map 型 15

Slide 16

Slide 16 text

© DMM sync.Map 型 16

Slide 17

Slide 17 text

© DMM sync.Map 型 17 メソッドでは基本 any を扱う

Slide 18

Slide 18 text

© DMM any で扱うことのなにが問題か? 18 ● メモリ割り当てが行われる ● 返り値の型アサーションがめんどう

Slide 19

Slide 19 text

© DMM any で扱うことのなにが問題か? 19 ● メモリ割り当てが行われる ● 返り値の型アサーションがめんどう

Slide 20

Slide 20 text

© DMM any で扱うことのなにが問題か? 20 ● メモリ割り当てが行われる ● 返り値の型アサーションがめんどう sync(v1) では any で扱ってしまっている ...

Slide 21

Slide 21 text

© DMM any で扱うことのなにが問題か? 21 ● メモリ割り当てが行われる ● 返り値の型アサーションがめんどう sync(v1) では any で扱ってしまっている ... インターフェースを介さないジェネリクスで扱い たい!

Slide 22

Slide 22 text

© DMM CONFIDENTAL インターフェースを 介したくない理由って ...?🤔

Slide 23

Slide 23 text

© DMM CONFIDENTAL インターフェースの メモリ割り当てについて

Slide 24

Slide 24 text

© DMM インターフェースのメモリ割り当て(雑) 24 ● インターフェースは「型」と「値」を持っている ● 「型」はメソッド情報へのポインタ ● 「値」は実際のデータへのポインタ (他の言語でのボックス化に近い概念かもしれません)

Slide 25

Slide 25 text

© DMM インターフェースのメモリ割り当て(雑) 25 String() メソッドを持つ構造体 A

Slide 26

Slide 26 text

© DMM インターフェースのメモリ割り当て(雑) 26 fmt.Stringer として新しく変数を作る

Slide 27

Slide 27 text

© DMM インターフェースのメモリ割り当て(雑) 27 s := fmt.Stringer(a) 型へのポインタ 値へのポインタ a.str などの値 fmt.Stringer a.String()

Slide 28

Slide 28 text

© DMM インターフェースのメモリ割り当て(雑) 28 s := fmt.Stringer(a) 型へのポインタ 値へのポインタ a.str などの値 fmt.Stringer 値へのポインタはヒー プ領域に確保 a.String()

Slide 29

Slide 29 text

© DMM インターフェースのメモリ割り当て(雑) 29 s := fmt.Stringer(a) 型へのポインタ 値へのポインタ a.str などの値 a.String() 値へのポインタはヒー プ領域に確保 ポインタ分のヒープ領域への 割り当てが発生する!

Slide 30

Slide 30 text

© DMM インターフェースのメモリ割り当て(雑) 30 s := fmt.Stringer(a) 型へのポインタ 値へのポインタ a.str などの値 a.String() 値へのポインタはヒー プ領域に確保 最適化で割り当てが 発生しない場合もあります

Slide 31

Slide 31 text

© DMM 最適化. 割り当てが発生しないこともある 31 ※ ワードサイズ: 32bit や 64bit などのCPUの処理単位

Slide 32

Slide 32 text

© DMM 最適化. 割り当てが発生しないこともある 32 i := any(v) 型へのポインタ 値へのポインタ 100 any

Slide 33

Slide 33 text

© DMM 最適化. 割り当てが発生しないこともある 33 i := any(v) 型へのポインタ 値へのポインタ 100 any 値をここに入れた方が 効率的!

Slide 34

Slide 34 text

© DMM 最適化. 割り当てが発生しないこともある 34 i := any(v) 型へのポインタ 100 any ポインタのヒープ 割り当てがなくなる

Slide 35

Slide 35 text

© DMM つまり..? 35 ● インターフェースを介すと、メモリ割り当てが発生! ○ (大体のケースで) ● 1回は小さくても頻繁に行われるなら大きく響くかも..?

Slide 36

Slide 36 text

© DMM CONFIDENTAL sync.Pool, sync.Map に話をもどして ...

Slide 37

Slide 37 text

© DMM any で扱うことのなにが問題か?(再掲) 37 ● メモリ割り当てが行われる ● 返り値の型アサーションがめんどう

Slide 38

Slide 38 text

© DMM any で扱うことのなにが問題か?(再掲) 38 ● メモリ割り当てが行われる ● 返り値の型アサーションがめんどう sync(v1) では any で扱ってしまっている ... インターフェースを介さないジェネリクスで扱い たい!

Slide 39

Slide 39 text

© DMM CONFIDENTAL sync/v2 パッケージのプロポーザル

Slide 40

Slide 40 text

© DMM 提案の概要 • sync.Pool, sync.Map をジェネリクス対応 • (sync.NewPool() があるのでただの移行ではないが、主題はジェネリク ス) • それ以外は据え置き 40

Slide 41

Slide 41 text

© DMM sync.Pool のジェネリクス対応 41

Slide 42

Slide 42 text

© DMM sync.Map のジェネリクス対応 42

Slide 43

Slide 43 text

© DMM 提案の内容(再掲) • sync.Pool, sync.Map をジェネリクス対応 • (sync.NewPool() があるのでただの移行ではないが、主題はジェネリク ス) • それ以外は据え置き 43

Slide 44

Slide 44 text

© DMM 提案の内容(再掲) • sync.Pool, sync.Map をジェネリクス対応 • (sync.NewPool() があるのでただの移行ではないが、主題はジェネリク ス) • それ以外は据え置き 44 ジェネリクス対応のためだけに v2 にするのか という意見もある

Slide 45

Slide 45 text

© DMM 議論の一部要約 45 ジェネリクス対応のためだけに v2にするべきか? 今後 sync/v3, net/http/v10, … のように 乱立してしまうのでは? ジェネリクスほどの大きな変更で はじめて sync/v3 になるので乱立しない

Slide 46

Slide 46 text

© DMM CONFIDENTAL ジェネリクス対応と v2

Slide 47

Slide 47 text

© DMM ジェネリクス対応とv2 • 2021年頃から sync/v2 とは別で議論がされている 47

Slide 48

Slide 48 text

© DMM 検討案 48 2. XxxOf 接尾辞 3. 型パラメータ デフォルト値 1. v2パッケージ をつくる

Slide 49

Slide 49 text

© DMM 案1. v2パッケージをつくる • まさしく sync/v2 のようにバージョンを分ける 49

Slide 50

Slide 50 text

© DMM 案1. v2パッケージをつくる • まさしく sync/v2 のようにバージョンを分ける 50 sync/v3, net/http/v10, ... のように乱立しそう

Slide 51

Slide 51 text

© DMM 案2. XxxOf 接尾辞 • PoolOf[T], MinOf[T] • XxxOf でジェネリクスとする • 元々ジェネリクスなものはそのまま Tree[K, V] 51

Slide 52

Slide 52 text

© DMM 案2. XxxOf 接尾辞 • PoolOf[T], MinOf[T] • XxxOf でジェネリクスとする • 元々ジェネリクスなものはそのまま Tree[K, V] 52 混乱しやすい

Slide 53

Slide 53 text

© DMM 案3. 型パラメータにデフォルト値 • ジェネリクス構文を拡張して互換性を保つ 53

Slide 54

Slide 54 text

© DMM 案3. 型パラメータにデフォルト値 • ジェネリクス構文を拡張して互換性を保つ 54 直感的でない

Slide 55

Slide 55 text

© DMM ジェネリクス対応とv2 • 結論は出ず... • sync/v2 パッケージでも同様の議論が生まれている • 差別化のために x/sync の Cond をいれてみてはという意 見も 55

Slide 56

Slide 56 text

© DMM CONFIDENTAL 感想とまとめ

Slide 57

Slide 57 text

© DMM 感想とまとめ • いろんな v2 パッケージのプロポーザルがある! • sync.Pool と sync.Map がジェネリクス対応するかも? • sync/v2 は今後のジェネリクス対応にも関わってきそうなので期 待 57

Slide 58

Slide 58 text

© DMM 参考 • https://github.com/golang/go/issues/71076 • https://research.swtch.com/interfaces • https://github.com/dominikh/go-tools/issues/302 • https://go-review.googlesource.com/c/go/+/24371?tab=comments • メモリアドレス - Wikipedia 58

Slide 59

Slide 59 text

© DMM ご清聴ありがとうございました!