Skip to content

fix: バッチ進捗が実態を表さずGUIを固める問題を解消(B-006) - #44

Merged
kumahide merged 2 commits into
mainfrom
fix/batch-progress-and-thread-offload
Jul 20, 2026
Merged

fix: バッチ進捗が実態を表さずGUIを固める問題を解消(B-006)#44
kumahide merged 2 commits into
mainfrom
fix/batch-progress-and-thread-offload

Conversation

@kumahide

Copy link
Copy Markdown
Owner

背景

実機β(2.4b1)で「バッチのプログレスバーが、初期に少し進んだ後ほぼ見えない速度で 100% になる/途中で一旦止まる」との報告。調査の結果、独立した3つの欠陥が重なっていた。

radiosim.log の実測(同一パス・同一 200 サンプル・キャッシュ暖機済み):

実行 所要
単一 約 1.0 s
バッチ(同一座標) 約 0.035 s

原因

1. バーが実作業量を追っていない

バッチのバーは DEM 標高取得のみを駆動源にしていたが、5 パスの取得は計 0.29 秒。体感時間の大半はバーの管轄外だった。

2. 成果物生成が GUI スレッドを塞いでいた(「一旦止まる」の正体)

save_path_visuals(matplotlib 断面図 PNG)を _on_path_done で、サマリ地図のタイル取得(ネットワーク)を _on_batch_complete で呼んでおり、その間メインスレッドが停止してバーの再描画すら止まっていた。

この配置は 「matplotlib はメインスレッド必須」という既に失効した制約に基づいていた。save_profile_png が pyplot(TkAgg) → Figure+FigureCanvasAgg へ移行した時点で Tk オブジェクトを生成しなくなっており、同一ファイル内で docstring 同士が矛盾していた。この構造は 2.0RC3 から存在し、2.0/2.1/2.2/2.3 の全リリースを生き延びている。

3. 単一実行が逆に不当に遅かった

simulation.fetch_elevationson_progressグローバルロック保持中に 1 サンプルごと呼ぶ。単一側はそこへ root.after(0, ...) を渡していたため、Tcl 呼び出しのコストが全ワーカーを直列化していた。上表の約30倍差の正体はこれで、「単一のバーが滑らかに動く」のはアニメーションを描くコストそのものだった。バッチは元からキュー方式で、単一だけが取り残されていた。

変更内容

  • 成果物生成(per-path PNG/HTML/KML・サマリ地図/HTML/KML)を batch のワーカースレッドへ移動。GUI コールバックは UI 更新のみに
  • 単一実行の進捗を root.after 直呼び → キュー+50ms ポーリングへ(プリフェッチ相も同様)
  • 失効していたメインスレッド制約の docstring / コメントを是正
  • バー配分=取得 15% / レポート描画 85%。描画は下位進捗を取れないので偽の進捗は出さずラベル(batch_stage_render / batch_stage_summary・en/ja)で状況を示す
  • テストの外部ネットワーク遮断ゲートを新設(下記)
  • README のテスト件数を実数へ同期(既存ドリフト含む・別コミット)

ネットワーク遮断ゲートを追加した理由

本修正で run_batch がサマリ地図の GSI タイル取得を含むようになり、ユニットテストが実ネットワークを叩き始めた。report_map はベストエフォート設計で取得失敗を None に落として続行するため、オンラインでもオフラインでもテストは緑のまま通る(所要時間の変化に気づかない限り検出不能)。socket 層で非 localhost 宛を遮断し、@pytest.mark.network でオプトアウト可能にした。

回帰ガード

  • test_artifacts_are_generated_off_the_main_thread — メインスレッドで生成されたら落ちる
  • test_progress_poll_does_not_overwrite_completion_state — 修正を外すと実際に落ちることを確認済み
  • test_network_guard_blocks_external_connections / _allows_localhost — ゲート自身の失効を防ぐ

検証

  • 499 passed / ruff clean / pyright 0 errors / pre-push LLM レビュー NO ISSUES
  • 実機確認済み(単一・バッチとも。修正中に作り込んだポーラ停止の回帰も実機で検出・修正済み)

注意事項

mpl_fonts.apply_japanese_font()matplotlib.rcParams(プロセス共有)を書き換えるため、パス単位のレポート描画を並列化してはならない(逐次実行を維持)。

残課題(2.4b3 へ)

本 PR は症状を潰したが、根本原因は単一とバッチで進捗実装が2本あること。ライフサイクルの非対称(バッチのポーラは永久に回る/単一は起動・停止する)が、修正中の回帰も生んだ。b3 で進捗トランスポートを1部品へ吸収する。パイプライン本体の統合は 2.5 の scenario.py へ委ねる。

🤖 Generated with Claude Code

kumahide and others added 2 commits July 20, 2026 20:19
バッチのプログレスバーは DEM 標高取得のみを駆動源にしていたが、ログ実測では
5パスの取得は計 0.29 秒で、体感時間の大半はバーの管轄外にあった。実時間を
占める成果物生成が GUI コールバック上にあり、メインスレッドを塞いでバーの
再描画ごと止めていた(=「一旦止まる」の正体)。

- 成果物生成(per-path PNG/HTML/KML・サマリ地図/HTML/KML)を batch の
  ワーカースレッドへ移動。GUI コールバックは UI 更新のみに。
  この配置は「matplotlib はメインスレッド必須」という制約に基づいていたが、
  save_profile_png が pyplot(TkAgg) から Figure+FigureCanvasAgg へ移行した
  時点で失効していた(Tk オブジェクトを生成しない)。docstring 同士が矛盾
  していたので実態へ是正。
- 単一実行の進捗を root.after 直呼びからキュー+50msポーリングへ。
  simulation.fetch_elevations は on_progress をグローバルロック保持中に
  1サンプルごと呼ぶため、Tcl 呼び出しのコストが全ワーカーを直列化していた。
  同一パス・200サンプルで単一 ≒1.0s / バッチ ≒0.035s(約30倍)の実測差の正体。
  プリフェッチ相も同じ病理だったので併せて修正。
- バー配分は取得15%/レポート描画85%。描画は下位進捗を取れないので偽の進捗は
  出さず、ラベル(batch_stage_render/summary)で状況を示す。
- 停止後に積み残しの進捗が完了表示を上書きする回帰を修正(実機βで検出)。
  _progress_stop(キュー破棄)+ _poll_progress の早期 return の二重防御。
  ワーカーは完了通知の後にも push しうるためキュー破棄だけでは不足。
- テストの外部ネットワーク遮断ゲートを新設。本修正で run_batch がサマリ地図の
  GSI タイル取得を含むようになり、ユニットテストが実ネットワークを叩き始めた
  ため。report_map はベストエフォート設計で失敗を None に落とすので
  オンライン/オフラインとも緑になり、沈黙して混入する。socket 層で遮断。

回帰ガード:
- test_artifacts_are_generated_off_the_main_thread(メインスレッド実行で落ちる)
- test_progress_poll_does_not_overwrite_completion_state(修正を外すと落ちる)
- test_network_guard_blocks_external_connections / _allows_localhost

⚠️ mpl_fonts.apply_japanese_font() が matplotlib.rcParams(プロセス共有)を
書き換えるため、パス単位のレポート描画は並列化してはならない。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs 整合ガードはテスト表のファイル名のみを検証しており件数は対象外のため、
表の件数が実態から乖離していた。本修正でのテスト追加分に加え、既存のずれも
まとめて実数へ揃える(総計 429 → 499)。

主なずれ: test_models 82→94 / test_dem 64→71 / test_batch 78→108(+2)
        / test_report_map 25→42 / test_docs_consistency 9→24
        / test_smoke 19→24(+5)

test_smoke.py の説明にネットワーク遮断ゲートの自己検査を追記。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kumahide
kumahide merged commit dba885e into main Jul 20, 2026
1 check passed
@kumahide
kumahide deleted the fix/batch-progress-and-thread-offload branch July 20, 2026 11:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant