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
synctestをEbitengineで可視化した話.pdf
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
nakadate00
March 18, 2026
91
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
synctestをEbitengineで可視化した話.pdf
nakadate00
March 18, 2026
More Decks by nakadate00
See All by nakadate00
チームが幸せになるカスタムエラーのススメ
nakadate_reo
0
180
Featured
See All Featured
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
450
Practical Orchestrator
shlominoach
192
12k
The Pragmatic Product Professional
lauravandoore
37
7.5k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
3.1k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
570
Producing Creativity
orderedlist
PRO
348
41k
Everyday Curiosity
cassininazir
0
360
Building the Perfect Custom Keyboard
takai
2
910
How STYLIGHT went responsive
nonsquared
100
6.3k
[RailsConf 2023] Rails as a piece of cake
palkan
59
7.1k
Odyssey Design
rkendrick25
PRO
2
880
Speed Design
sergeychernyshev
33
2.2k
Transcript
synctest を Ebitengine で可視化した話 Go Connect #11 2026. 03. 18
01 自己紹介 02 解決策 03 デモ 04 可視化した結果 05 まとめ 目次 Index
自己紹介 Self Introduction 01
4 自己紹介 名前:date(@nakadate00) 趣味:京都観光・音楽ライブ 所属:株式会社BuySell Technologies 技術:Go・Python・TypeScript(Hono)・Unity C#
突然ですが synctest 理解できていますか?
https://go.dev/blog/synctest synctestとは • Go1.24で実験的に導入され、Go1.25で正式リリース • Go言語の並行処理テスト を支援するパッケージ • 2つの関数で構成 ◦
bubble 内でテストを実行する Test 関数(旧 Run 関数) ◦ bubble 内の全てのゴルーチンがブロックされるまで待機する Wait 関数 • すべてのゴルーチンが durably block になったら進む fake clock による時間制御(初期時刻: UTC 2000-01-01 00:00:00)
すべてのゴルーチンが durably block になったら進む fake clock 🤔 https://pkg.go.dev/testing/synctest#hdr-Time
すべてのゴルーチンが durably block になったら進む fake clock 🤔 https://pkg.go.dev/testing/synctest#hdr-Time → ドキュメントやコードだけでは理解が進まなかった
解決策 Solution 02
10 • Go の並行処理を Ebitengine で可視化している発表を見た • synctest だけでなく Ebitengine
もずっと触ってみたかった Ebitengine で可視化すればいいじゃない! https://ebitengine.org/ja/
11 キャッシュ処理の非同期テスト ベースとなるコードは以下を参考にし た簡単なキャッシュ処理 Go1.25新機能 testing/synctest で高速& 確実な並行テストを実現する方法
12 キャッシュ処理の非同期テスト ベースとなるコードは以下を参考にし た簡単なキャッシュ処理 Go1.25新機能 testing/synctest で高速& 確実な並行テストを実現する方法 1. メインゴルーチンが爆弾を宝箱に入れ
る (キャッシュにデータをセット) 2. サブゴルーチンが爆弾を解除 (キャッシュをクリア) 3. メインゴルーチンが宝箱を確認 (キャッシュのデータを確認) = キャッシュ = データ
13 Ebitengine で可視化するためにログを出力 synctest は test パッケージのみ利用可 ※その他、シミュレーション開始時や終了 時、爆弾解除時などのログも出力
デモ Demonstration 03
15 デモ(処理の流れイメージ)
16 1秒余裕を持って待機 1. メインゴルーチンが爆弾を宝箱に入れ る 2. サブゴルーチンが爆弾を解除 3. 余裕を持って 1秒待機してから
メインゴルーチンが宝箱を確認 非同期処理のテストを100%成功させるた めの従来の手法
17 1秒の待機を無くす 1. メインゴルーチンが爆弾を宝箱に入れ る 2. サブゴルーチンが爆弾を解除 3. メインゴルーチンが宝箱を確認 テストの成功
/失敗はランダムになる
18 デモ(爆弾解除成功)
19 デモ(爆弾解除失敗)
20 なぜテストの成功 /失敗はランダムになったのか 1秒待つパターン 待たないパターン ギリギリをせめすぎなのでは??
21 durably block に着目してみる • Go1.24で実験的に導入され、Go1.25で正式リリース • Go言語の並行処理テスト を支援するパッケージ •
2つの関数で構成 ◦ bubble 内でテストを実行する Test 関数(旧 Run 関数) ◦ bubble 内の全てのゴルーチンがブロックされるまで待機する Wait 関数 • すべてのゴルーチンが durably block になったら進む fake clock による時間制御(初期時刻: UTC 2000-01-01 00:00:00)
https://go.dev/blog/synctest durably blockとは The complete list of operations which durably
block a goroutine is: • a send or receive on a nil channel • a send or receive blocked on a channel created within the same bubble • a select statement where every case is durably blocking • time.Sleep • sync.Cond.Wait • sync.WaitGroup.Wait
https://go.dev/blog/synctest durably blockとは ゴルーチンを永続的にブロックする操作の完全なリストは以下: • nil チャネルでの送信または受信 • 同一 bubble
内で作成されたチャネルで、ブロックされた送信または受信 • すべてのケースが永続的にブロックする select 文 • time.Sleep • sync.Cond.Wait • sync.WaitGroup.Wait
https://go.dev/blog/synctest durably blockとは ゴルーチンを永続的にブロックする操作の完全なリストは以下: • nil チャネルでの送信または受信 • 同一 bubble
内で作成されたチャネルで、ブロックされた送信または受信 • すべてのケースが永続的にブロックする select 文 • time.Sleep • sync.Cond.Wait • sync.WaitGroup.Wait 今回使用している操作は time.Sleep のみ
25 1秒待つパターンの durably block のタイミング メインゴルーチン サブゴルーチン Set time.Sleep (start)
time.Sleep (end)i Get time.Sleep (start) time.Sleep (end) c.value = "" 1秒待機
26 メインゴルーチンが Set メインゴルーチン サブゴルーチン Set time.Sleep (start) time.Sleep (end)i
Get time.Sleep (start) time.Sleep (end) c.value = "" 1秒待機
27 メインかサブのどちらかが先に time.Sleep (durably block) durably block Set time.Sleep (start)
time.Sleep (end)i Get time.Sleep (start) time.Sleep (end) c.value = "" 1秒待機 メインゴルーチン サブゴルーチン サブが durably block ではない 時刻は進まない
28 メインかサブのどちらかが先に time.Sleep (durably block) Set time.Sleep (start) time.Sleep (end)i
Get time.Sleep (start) time.Sleep (end) c.value = "" 1秒待機 メインゴルーチン サブゴルーチン durably block メインが durably block ではない 時刻は進まない
29 すべてのゴルーチンが durably block になったので時刻が進む Set time.Sleep (start) time.Sleep (end)i
Get time.Sleep (start) time.Sleep (end) c.value = "" 1秒待機 メインゴルーチン サブゴルーチン durably block durably block
30 サブゴルーチンが待機を完了して動き出す Set time.Sleep (start) time.Sleep (end)i Get time.Sleep (start)
time.Sleep (end) c.value = "" 1秒待機 メインゴルーチン サブゴルーチン
31 メインゴルーチンが 1秒待機中に爆弾解除 Set time.Sleep (start) time.Sleep (end)i Get time.Sleep
(start) time.Sleep (end) c.value = "" 1秒待機 メインゴルーチン サブゴルーチン
32 メインゴルーチンが 1秒の待機を完了して動き出す Set time.Sleep (start) time.Sleep (end)i Get time.Sleep
(start) time.Sleep (end) c.value = "" 1秒待機 メインゴルーチン サブゴルーチン
33 爆弾解除を待ってから確認しているため無事に成功 Set time.Sleep (start) time.Sleep (end)i Get time.Sleep (start)
time.Sleep (end) c.value = "" 1秒待機 メインゴルーチン サブゴルーチン
34 待たないパターンの durably block のタイミング メインゴルーチン サブゴルーチン Set time.Sleep (start)
time.Sleep (end)i Get time.Sleep (start) time.Sleep (end) c.value = ""
35 メインゴルーチンが Set メインゴルーチン サブゴルーチン Set time.Sleep (start) time.Sleep (end)i
Get time.Sleep (start) time.Sleep (end) c.value = ""
36 メインかサブのどちらかが先に time.Sleep (durably block) メインゴルーチン サブゴルーチン Set time.Sleep (start)
time.Sleep (end)i Get time.Sleep (start) time.Sleep (end) c.value = "" durably block サブが durably block ではない 時刻は進まない
37 メインかサブのどちらかが先に time.Sleep (durably block) メインゴルーチン サブゴルーチン Set time.Sleep (start)
time.Sleep (end)i Get time.Sleep (start) time.Sleep (end) c.value = "" durably block メインが durably block ではない 時刻は進まない
38 すべてのゴルーチンが durably block になったので時刻が進む メインゴルーチン サブゴルーチン Set time.Sleep (start)
time.Sleep (end)i Get time.Sleep (start) time.Sleep (end) c.value = "" durably block durably block
39 メインとサブがともに待機を完了して動き出す メインゴルーチン サブゴルーチン Set time.Sleep (start) time.Sleep (end)i Get
time.Sleep (start) time.Sleep (end) c.value = ""
40 爆弾解除と確認が同タイミングになり失敗 メインゴルーチン サブゴルーチン Set time.Sleep (start) time.Sleep (end)i Get
time.Sleep (start) time.Sleep (end) c.value = ""
41 無事に成功させるためには爆弾解除を待つための何かが必要 メインゴルーチン サブゴルーチン Set time.Sleep (start) time.Sleep (end)i Get
time.Sleep (start) time.Sleep (end) c.value = "" サブゴルーチンの完了を待つ 何かが欲しい
42 そこで Wait 関数が役に立つ • Go1.24で実験的に導入され、Go1.25で正式リリース • Go言語の並行処理テスト を支援するパッケージ •
2つの関数で構成 ◦ bubble 内でテストを実行する Test 関数(旧 Run 関数) ◦ bubble 内の全てのゴルーチンがブロックされるまで待機する Wait 関数 • すべてのゴルーチンが durably block になったら進む fake clock による時間制御(初期時刻: UTC 2000-01-01 00:00:00)
43 synctest.Wait を利用 1. メインゴルーチンが爆弾を宝箱に入れ る 2. サブゴルーチンが爆弾を解除 3. 爆弾解除の実施完了を確認する
synctest.Wait 4. メインゴルーチンが宝箱を確認 Wait 関数を利用 →bubble 内の全てのゴルーチンが ブロックされるまで待機 →爆弾解除の実施中はブロック判定 ではないので待機 →爆弾解除の実施完了を確認してから 次の処理に進む
44 デモ(synctest.Wait を使用することで 100%成功)
可視化した結果 Results 04
46 よかったこと 以下の流れを 理解することができた すべてのゴルーチンが durably block になったら bubble 内の時刻が進む →
つまり、同時にキャッシュ取得と削除の処理が実行 される → そのため、キャッシュ削除が少しでも遅れると取得時にエラーになる → キャッシュ削除ゴルーチンの処理完了を待つ synctest.Wait で解決
47 よかったこと 以下の流れを可視化しつつ 理解することができた すべてのゴルーチンが durably block になったら bubble 内の時刻が進む
→ つまり、同時にキャッシュ取得と削除の処理が実行 される 宝箱を再確認するメインと、宝箱から爆弾を取り除くサブが同時に動く → そのため、キャッシュ削除が少しでも遅れると取得時にエラーになる 宝箱から爆弾を取り除く前にメインゴルーチンが再確認してしまい爆発 → キャッシュ削除ゴルーチンの処理完了を待つ synctest.Wait で解決 メインゴルーチンが爆弾解除処理を待つ ことで安全に宝箱を再確認できる
48 • 本当は動的に synctest の処理を可視化したかった …。 ◦ testing/synctest がテストファイル専用のものだったので断念 •
synctest.Wait での待ち時間を明確に可視化したかった …。 ◦ キャッシュ再取得のメインゴルーチンを余剰に待たせると synctest.Wait で待たなくても絶対に成功する(従来の手法) ◦ キャッシュ削除のサブゴルーチンを余剰に待たせるとその間 durably block 状態になるため、 synctest.Wait が即座にスルー → サブゴルーチンの処理が重い場合は待ち時間を可視化できそう うまくいかなかったこと(学び)
まとめ Conclusion 05
50 まとめ • Go の複雑な処理で理解に苦しんだ時は別の視点から考えてみると良さそう ◦ その視点を与えてくれる一つが Ebitengine だと感じた •
「実際に手を動かして色々試しながらコードを書くこと」が一番理解を進める
51 参考資料 • Testing concurrent code with testing/synctest • testing/synctest
• Ebitengine • Go1.25新機能 testing/synctest で高速&確実な並行テストを実現する方法 • wuhan005/❤Gopher.GIF • かわいいフリー素材集 いらすとや
🍤ご清聴ありがとうございました 🍤 designed by Renee French.