Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Go1.10 strings.Builder の紹介
Search
Kenshi Kamata
February 20, 2018
Programming
1.5k
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
3.1k
チャネルの仕組み
knsh14
6
5.6k
Go でインタプリタを 書いてみよう
knsh14
0
3.1k
Let’s Create An Interpreter In Go
knsh14
0
170
Go Code Review Comment を翻訳した話
knsh14
0
7.7k
tvOS Leaderboard
knsh14
0
1.2k
Other Decks in Programming
See All in Programming
すこし踏み込む CancellationToken
htkym
2
880
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
2.3k
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
450
UPDATE をやめる — EF Core でマスタをバージョン管理する
panda728
PRO
0
490
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
300
速習iPhone Duo対応
yuukiw00w
1
710
ゲームコントローラやキーボードのファームウェアをSwiftで書く
kishikawakatsumi
1
250
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
110
Jetpack Compose メカニズム
skydoves
0
470
AI Agent時代のリアーキテクチャ戦略と実践
hokaccha
9
4.9k
新卒PdEのリアル
ryu1013
1
510
Agents on Rails - Rails at Scale 2026
irinanazarova
0
180
Featured
See All Featured
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
How to make the Groovebox
asonas
2
2.4k
Utilizing Notion as your number one productivity tool
mfonobong
4
590
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
18k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
460
Docker and Python
trallard
47
4.2k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
67
58k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Heart Work Chapter 1 - Part 1
lfama
PRO
10
36k
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言語のメモリ管理 を 参考にしました