fix: バッチ進捗が実態を表さずGUIを固める問題を解消(B-006) - #44
Merged
Merged
Conversation
バッチのプログレスバーは 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
実機β(2.4b1)で「バッチのプログレスバーが、初期に少し進んだ後ほぼ見えない速度で 100% になる/途中で一旦止まる」との報告。調査の結果、独立した3つの欠陥が重なっていた。
radiosim.logの実測(同一パス・同一 200 サンプル・キャッシュ暖機済み):原因
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_elevationsはon_progressをグローバルロック保持中に 1 サンプルごと呼ぶ。単一側はそこへroot.after(0, ...)を渡していたため、Tcl 呼び出しのコストが全ワーカーを直列化していた。上表の約30倍差の正体はこれで、「単一のバーが滑らかに動く」のはアニメーションを描くコストそのものだった。バッチは元からキュー方式で、単一だけが取り残されていた。変更内容
batchのワーカースレッドへ移動。GUI コールバックは UI 更新のみにroot.after直呼び → キュー+50ms ポーリングへ(プリフェッチ相も同様)batch_stage_render/batch_stage_summary・en/ja)で状況を示すネットワーク遮断ゲートを追加した理由
本修正で
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— ゲート自身の失効を防ぐ検証
注意事項
mpl_fonts.apply_japanese_font()がmatplotlib.rcParams(プロセス共有)を書き換えるため、パス単位のレポート描画を並列化してはならない(逐次実行を維持)。残課題(2.4b3 へ)
本 PR は症状を潰したが、根本原因は単一とバッチで進捗実装が2本あること。ライフサイクルの非対称(バッチのポーラは永久に回る/単一は起動・停止する)が、修正中の回帰も生んだ。b3 で進捗トランスポートを1部品へ吸収する。パイプライン本体の統合は 2.5 の
scenario.pyへ委ねる。🤖 Generated with Claude Code