Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Go1.10 strings.Builder の紹介
Search
Kenshi Kamata
February 20, 2018
Programming
1.4k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Go1.10 strings.Builder の紹介
Go 1.10 Release Party in Tokyo の発表です
Kenshi Kamata
February 20, 2018
More Decks by Kenshi Kamata
See All by Kenshi Kamata
500万ユーザーを支える残高の冪等性 / The idempotency of the balance for 5 million Merpay users
knsh14
0
3k
チャネルの仕組み
knsh14
6
5.6k
Go でインタプリタを 書いてみよう
knsh14
0
3.1k
Let’s Create An Interpreter In Go
knsh14
0
160
Go Code Review Comment を翻訳した話
knsh14
0
7.7k
tvOS Leaderboard
knsh14
0
1.2k
Other Decks in Programming
See All in Programming
A2UI という光を覗いてみる
satohjohn
1
160
act1-costs.pdf
sumedhbala
0
120
鹿野さんに聞く!『TypeScriptコードレシピ集』で磨く実践力
tonkotsuboy_com
4
840
JavaDoc 再入門
nagise
1
420
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
120
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
1
310
The ROI of Quarkus for Spring Boot Applications
hollycummins
0
140
Datadog × OpenTelemetry 入門と実践のあいだ
kn_to_maxpno
1
180
Go1.27で導入されるジェネリクスメソッドでできること
mackee
0
190
なぜ型を書くのか? TSKaigi2026で改めて考える #tskaigi_smarthr
kajitack
0
160
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
970
代数的データ型って何が嬉しいの? #frontend_phpcon_do
kajitack
8
3.8k
Featured
See All Featured
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
180
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
440
The Language of Interfaces
destraynor
162
27k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.3k
Designing Experiences People Love
moore
143
24k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.7k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
170
Test your architecture with Archunit
thirion
1
2.3k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.8k
Side Projects
sachag
455
43k
Navigating Team Friction
lara
192
16k
Transcript
strings.Builder の紹介 Golang 1.10 release party 鎌田 健史
自己紹介 • 鎌田 健史 • @knsh14 (twitter, GitHub) • KLab
株式会社 ◦ Unity のエディタ拡張書いたり ◦ JavaScript でゲーム書いたり • 技術書典ではバイトしてました
strings.Builder って何 ? • https://golang.org/pkg/strings/#Builder • 1.10 から入った新しいデータ型 • 文字列を構築するために使われる
strings.Builder の使い方 https://github.com/knsh14/monkey/blob/master/ast/ast.go#L182-L1 96 こういう箇所を string.Builder で置き換えたい
bytes.Buffer との比較 bytes.Buffer strings.Builder io.Writer を実装している ◯ ◯ io.Reader を実装している
◯ ✕ 初期値を与える NewXXX(s string) ◯ ✕
strings.Builder を作った理由 • Issue ◦ https://github.com/golang/go/issues/18990 ◦ https://go-review.googlesource.com/c/go/+/74931 • bytes.Buffer
に溜め込んだ文字列を string にする時に発生する余 計なアロケーションを回避したい
パフォーマンス見てみる https://gist.github.com/knsh14/fd4b0413a32b8b2ca544f2706d8557 d0 1. 100 回 WriteString してその結果を n 回取り出す
2. n 回 WriteString してその結果を String() で取り出す 3. 事前に n * 10 で容量を確保しておき、2と同じことをする 4. これを 10, 100, 1000, 10000, 100000 回で試す
1. については確かに早くなっている • 回数が多くなればなるほど差が開いていく • 10万回 String() すると 400倍近い差がでる •
Allocation は 100000 回呼ぶと 約 1/12500
なぜだろう? • bytes.Buffer の String → メモリコピーが走る ◦ String(b []byte)している
• strings.Builder の String → メモリコピーが走らない ◦ unsafe.Pointer からのキャスト • ちょうど修正したところが活かされている
もう一つのベンチマーク • n 回 WriteString して書き込んで一度だけ String() を読んで文字列 を取得すると若干遅くなる •
特に allocation とメモリのパフォーマンスが落ちる • 事前に Grow(n int) している場合には遅くならない ◦ Grow は Buffer の cap を増やす処理 • 実装を調べてみる
bytes.Buffer の WriteString • https://golang.org/src/bytes/buffer.go?s=6183:6240#L172 • cap にまだ書き込める余裕があるかチェック • 余裕がなければ
make で cap を増やす • 増えたら copy で書き込む
strings.Builder の WriteString • https://tip.golang.org/src/strings/builder.go?s=3201:3253#L105 • 自分自身がコピーされたものじゃないかチェック • append する
実装の比較 • bytes.Buffer の grow は cap を増やす時に もとの長さ *
2 + 増や す分 の長さを取っている ◦ https://golang.org/src/bytes/buffer.go?s=4258:4292#L144 • strings.Builder は append(d []byte, s string) • 繰り返しが小さいと差が出づらい ◦ 小さい要素だと append も倍増やす仕組みになっているらしい • この差で bytes.Buffer は少し make する回数が減っているのでは ないか?
どう使い分けるのがいいのか? • どれくらい buffer に書き込むか事前にわからない場合は bytes.Buffer のほうが少し有利 • String() を何回も呼ぶ必要がある場合には
strings.Builder のほう が圧倒的に有利 • 事前にどれくらい書き込むかわかっている場合には strings.Builder がおすすめ
更に細かい実装の話
コピーされたかどうか検知する • https://play.golang.org/p/nzYsBpxYZpc • struct をコピーすると、フィールドがポインタの場合はアドレスがコ ピーされる ◦ フィールドのアドレスが共有され、思わぬ副作用が •
これを回避したい ◦ 最初に書き込むときに自分自身のアドレスを持っておく ◦ B := A とコピーする ◦ B 自身のポインタとフィールドが持っているポインタが違うのでコ ピーされたことが検出できる
noescape を使ってパフォーマンス改善 • https://github.com/golang/go/issues/23382 • https://go-review.googlesource.com/c/go/+/86976 • コピーされてないかチェックするだけでメモリ確保が走ってしまうのを 防ぐ •
`//go:nosplit` がついてる関数ではスタックの操作はしない ◦ Goならわかるシステムプログラミング Go言語のメモリ管理 を 参考にしました