加快门禁:删除测试窗口、释放桩线程并并行运行三个阶段

关闭后未删除的测试窗口让每次主题切换重排全部残留控件,ui_check 每次关窗还要等桩线程 5 秒。Linux 上结论不变,test_ui_smoke 75→64 s、ui_check 52→16 s;Windows 门禁结果见 .scratch/gate-speed/。
This commit is contained in:
ykcheungab
2026-10-19 09:34:29 +08:00
parent d89535236b
commit a0c13c1dc6
6 changed files with 160 additions and 44 deletions
+38 -22
View File
@@ -414,6 +414,22 @@ DECORATIVE_PAIRS: tuple[tuple[str, tuple[str, ...]], ...] = (
)
def _close_window(window) -> None:
"""Close a check window, releasing its stand-in worker first.
A ``_StuckWorker`` hangs on purpose, and the window's shutdown path stops its
worker with ``wait=True``, which joins that thread for up to 5 s. Every scene that
closed a window on a still-hanging stub paid those 5 s (measured: 7 joins, 35 s of
a 52 s run). What those scenes check happens before the close, so the stub is let
go here; the shutdown itself is checked separately in a subprocess.
"""
for name in ("_box_worker", "_finger_worker"):
worker = getattr(window, name, None)
if isinstance(worker, _StuckWorker):
worker.release()
window.close()
def _srgb_channel(value: int) -> float:
channel = value / 255.0
if channel <= 0.03928:
@@ -836,7 +852,7 @@ def main() -> int:
len(window.prefs.get("splitter_sizes", [])) == 4,
"splitter sizes not persisted",
)
window.close()
_close_window(window)
app.processEvents()
section("small window")
@@ -885,7 +901,7 @@ def main() -> int:
f" in {type(parent).__name__} {parent.width()}x{parent.height()}"
)
check(not oversize, f"widgets overflow their parent: {oversize}")
window.close()
_close_window(window)
app.processEvents()
section("top area")
@@ -1072,7 +1088,7 @@ def main() -> int:
not window.toolbar.settings_expanded(),
f"{theme}: the settings area could not be collapsed again",
)
window.close()
_close_window(window)
app.processEvents()
# English labels are the widest case ("Start recording", "Sensor config"),
@@ -1096,7 +1112,7 @@ def main() -> int:
f"the sensor summary is not stated in full: "
f"{english_window.toolbar.btn_sensor.text()!r}",
)
english_window.close()
_close_window(english_window)
app.processEvents()
set_locale("zh_CN")
@@ -1153,7 +1169,7 @@ def main() -> int:
f" reset label at 1280x720, {language}: live {live_width}px, "
f"replay {replay_width}px (button width {button.width()}px)"
)
measured.close()
_close_window(measured)
app.processEvents()
set_locale("zh_CN")
@@ -1320,7 +1336,7 @@ def main() -> int:
window.toolbar.set_record_checked(False)
window._stop_run(reason="user_stop")
stuck.release()
window.close()
_close_window(window)
app.processEvents()
section("stopping a hung connect")
@@ -1388,7 +1404,7 @@ def main() -> int:
"Esc did not cancel the hung connect immediately",
)
check(not window._running, "Esc left the session running")
window.close()
_close_window(window)
app.processEvents()
# Let the deliberately-stuck thread finish before the interpreter tears
@@ -1491,7 +1507,7 @@ def main() -> int:
"the depth colour scale re-fitted per frame instead of staying fixed",
)
window.close()
_close_window(window)
app.processEvents()
stuck.release()
@@ -1797,14 +1813,14 @@ def main() -> int:
"the 2D image area does not follow the output image's aspect ratio: "
f"{image.width()}x{image.height()}",
)
finger_window.close()
_close_window(finger_window)
app.processEvents()
check(
window.toolbar.record_chip.text() == t("record.state_idle"),
f"the record strip did not fall back to idle: "
f"{window.toolbar.record_chip.text()!r}",
)
window.close()
_close_window(window)
app.processEvents()
section("chart header and unit chip")
@@ -1892,7 +1908,7 @@ def main() -> int:
# The locale is process-wide: leave it where the other sections expect it.
header_window._set_language("zh_CN")
app.processEvents()
header_window.close()
_close_window(header_window)
app.processEvents()
section("acquisition correctness")
@@ -2156,7 +2172,7 @@ def main() -> int:
pane_window.replay.close()
pane_window._stop_run(reason="user_stop")
stuck.release()
pane_window.close()
_close_window(pane_window)
app.processEvents()
_shutil.rmtree(replay_root, ignore_errors=True)
@@ -2323,7 +2339,7 @@ def main() -> int:
)
check(meta["stats"]["frames"] == 31, f"unexpected frame count: {meta['stats']['frames']}")
window.close()
_close_window(window)
app.processEvents()
stuck.release()
_shutil.rmtree(scratch, ignore_errors=True)
@@ -2430,7 +2446,7 @@ def main() -> int:
f"the session phase is {fail_window._session_phase!r} after a failed recording",
)
fail_window.close()
_close_window(fail_window)
app.processEvents()
stuck_fail.release()
_app_module.recordings_dir = lambda: scratch
@@ -2605,7 +2621,7 @@ def main() -> int:
f"a matching calibration was not requested: {stuck_identity.calibration_requests}",
)
identity_window.close()
_close_window(identity_window)
app.processEvents()
_shutil.rmtree(record_dir, ignore_errors=True)
@@ -2657,7 +2673,7 @@ def main() -> int:
units_plots.history.sample_count > 0,
"the rebuilt history lost every sample",
)
units_window.close()
_close_window(units_window)
units_window._box_worker = None
stuck_units.release()
app.processEvents()
@@ -2716,7 +2732,7 @@ def main() -> int:
and not any(_math.isfinite(v) for v in one_state.values[:, 1]),
"FX carried a value without a calibration curve",
)
one_window.close()
_close_window(one_window)
one_window._box_worker = None
stuck_one.release()
app.processEvents()
@@ -2903,7 +2919,7 @@ def main() -> int:
check(plots._source_ready, "switching units detached the curve source")
check(plots._unit == "N", f"the unit switch did not reach the charts: {plots._unit}")
window.close()
_close_window(window)
app.processEvents()
stuck.release()
@@ -2996,7 +3012,7 @@ def main() -> int:
"the way back to the camera did not take effect",
)
window.close()
_close_window(window)
app.processEvents()
stuck.release()
@@ -3141,7 +3157,7 @@ def main() -> int:
pane.close_view()
check(True, "closing the 3D pane twice is safe")
finally:
pane_window.close()
_close_window(pane_window)
app.processEvents()
section("replay")
@@ -3325,7 +3341,7 @@ def main() -> int:
)
other_window.replay_ctl.stop_activity()
app.processEvents()
other_window.close()
_close_window(other_window)
app.processEvents()
replay_window.activateWindow()
app.processEvents()
@@ -3706,7 +3722,7 @@ def main() -> int:
)
replay_window.replay.close()
replay_window.close()
_close_window(replay_window)
app.processEvents()
_shutil.rmtree(replay_root, ignore_errors=True)