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
testing/synctest使ってみた
Search
Pana
March 07, 2025
0
52
testing/synctest使ってみた
Pana
March 07, 2025
Tweet
Share
More Decks by Pana
See All by Pana
Deep dive into log/slog package
k3forx
1
370
Featured
See All Featured
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.4k
Faster Mobile Websites
deanohume
309
31k
Building Adaptive Systems
keathley
43
2.7k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
900
How to train your dragon (web standard)
notwaldorf
96
6.2k
Docker and Python
trallard
45
3.5k
Designing Experiences People Love
moore
142
24k
Producing Creativity
orderedlist
PRO
347
40k
A better future with KSS
kneath
239
17k
Java REST API Framework Comparison - PWX 2021
mraible
33
8.8k
A Modern Web Designer's Workflow
chriscoyier
695
190k
Transcript
2025.03.07 presented by Pana testing/synctest使ってみた 第2回Beerbash
⾃⼰紹介 ‧名前(ニックネーム) ‧Pana (miyaharaさんとよく間違えられるため) ‧名字で呼んでもらっても⼤丈夫です ‧基本情報 ‧1996年⽣まれ、広島出⾝ ‧業務 ‧カナリー、マーケットプレイスチーム ‧趣味
‧コーヒー、つけ麺、美味しいもの⾷べる
Go1.24リリース🎉
Go1.24のリリースサマリ 今回はtesting/synctestパッケージを紹介! ‧型エイリアスがジェネリクスに対応 ‧tools.goで管理していた依存関係がgo.modで管理できるように ‧イテレータ関連のメソッドが追加 ‧mapの実装がSwiss Tableになってパフォーマンスが向上 ‧実験的なパッケージとしてtesting/synctestが導⼊ ‧etc...
testing/synctestの紹介
testing/synctestの概要 ‧実装の背景 ‧concurrentな実装のテストは時間がかかる ‧flakyになりがち ‧注意点 ‧まだ実験的に導⼊されているので挙動が正しくないことがある
testing/synctestの概要 実際に試してみる! ‧公開されている関数は2つ ‧Run ‧Wait ‧実⾏時には GOEXPERIMENT=synctest フラグを渡す必要がある
実験1: 簡単なキャッシュ
実験1: 簡単なキャッシュ(実装コード) ‧SetとGetのみ ‧Setが呼ばれた時に setTime = time.Now() が実⾏される ‧Getが呼ばれた時、TTL経過していたらゼ ロ値、そうでない場合は
c.v が返される
実験1: 簡単なキャッシュ(テストコード) ‧xxx ‧xxx ‧xxx テストの実⾏に5秒以上かかる 😢 実⾏してみる
実験1: 簡単なキャッシュ(テストコード) Run関数でWrapすると、約0.17秒でテストが終わる 🎉 実⾏してみる
synctest.RunのGoDocをみてみる
synctest.RunのGoDocをみてみる(⼀部翻訳) 1. Runは関数fを新しいゴルーチンの中で実⾏する 2. 新しいゴルーチンとそれから間接的に開始されたゴルーチンはbubbleを形 成する 3. Runはbubbleの中のすべてのゴルーチンがexitするまで待つ 4. bubbleの中のゴルーチンはsyntheticな時間実装を使う、初期時間はUTCの
2000-01-01 5. bubbleの中のすべてのゴルーチンがブロックされたら時間が進む 4, 5を検証してみる 💡
実験1: 簡単なキャッシュ(テストコード) time.Sleepによってブロックすると時間が進む! 実⾏してみる
実験1: 簡単なキャッシュ(テストコード) もうちょっとpracticalな例を考えてみる ‧今回の実験で分かったこと ‧Runを使えばテストにかかる時間を短縮できる ‧Runの挙動(⼀部のみ) ‧ここで疑問 🤔 ‧「別にTTLを5秒にしなくても、1マイクロ秒にすればいいやん」 →
その通りです!今回の実装の場合 testing/synctest パッケージは不要 → なぜなら、そもそもの実装が直列で実⾏されるから
実験2: 簡単なキャッシュv2
実験2: 簡単なキャッシュv2(実装コード) ‧Setが呼ばれた時に、別のゴルーチン でexpireさせる (ゼロ値に更新する) ‧「何かの関数を呼んだ際に、別のゴ ルーチンが作られる」という挙動を具 体化した1つの例として考えてみる
実験2: 簡単なキャッシュv2(テストコード) 100回中4回落ちた = flakyなテストになっている 😢 100回実⾏してみる v1と同じテスト!
なぜランダムで落ちるのか? 「Get」と「c.v = zero」のどちらが先 に実⾏されるか不明 = flakyになる原因 (Runの仕様その5) bubbleの中のすべてのゴルーチンがブロック されたら時間が進む
実験2: 簡単なキャッシュv2(テストコード) 落ちなくなった 🎉 直感的には「ゴルーチンの終了を待つ」挙動だが...? 100回実⾏してみる
synctest.WaitのGoDocをみてみる
synctest.WaitのGoDocをみてみる(⼀部翻訳) 1. Waitは、現在のbubble内の現在のゴルーチン以外のすべてのゴルーチンが 持続的にブロック (durably block) されるまでブロックする 2. bubble外のゴルーチンから呼び出された場合や、同じbubble内の2つのゴ ルーチンが同時にWaitを呼び出した場合はパニックする
3. bubble内の他のゴルーチンによってのみブロックを解除できる場合、その ゴルーチンはdurably blockされる 4. time.Sleepやbubble内からのチャネルの送受信などはゴルーチンを durably blockする 「ゴルーチンの終了を待つ」とは書かれていない! 1, 4を元にもう⼀度考えてみる!
synctest.Waitの挙動 1. Waitが呼ばれた時、サブのゴルーチ ンは実⾏中なら2、終了したなら4へ 2. サブのゴルーチンがdurably blockedになるまで待つ 3. durably blockedになることなく、
サブのゴルーチンが終了 4. Waitはサブのゴルーチンを気にする 必要がなくなってunblock 5. メインのゴルーチンの処理が進む (Runの仕様その5) bubbleの中のすべてのゴルーチンがブロックされたら時間が進む
おさらい! Q1. テストでSetだけ呼んだ時、下記で出⼒される時刻はどうなるか? 正解はC A. テストを実⾏した時の時刻 B. 2000-01-01 00:00:00 (UTC)
C. 2000-01-01 00:00:05 (UTC) (Runの仕様その3) Runはbubbleの中のすべてのゴルーチンがexitするまで待つ → サブのゴルーチンのtime.Sleepを待つ
おさらい! Q2. メインのゴルーチンのtime.Sleepを外すとどうなるか? 正解はA A. テストが落ちる B. flakyなテストになる C. テストは落ちない
(Waitの仕様その1) Waitは、現在のbubble内の現在のゴルーチン以外のすべてのゴルー チンが持続的にブロック (durably block) されるまでブロックする → サブのゴルーチンがブロックされたら、メインのゴルーチンの処 理が進む
まとめ
testing/synctestパッケージのまとめ 1. testing/synctestを使うとテストにかかる時間を短縮できる 2. synctest.Runの中のすべてのゴルーチンがブロックされてから、時刻が進む 3. synctest.Waitはゴルーチンの終了を待つわけではない a. durably blockになるのを待つ
4. GoDoc読むの⼤切 a. 直感的なコードの挙動と実際の挙動が違っていた 実際に導⼊されるかは分からないが⾯⽩い機能でした 😆
ありがとうございました