Окно показывается после сборки интерфейса, а не до неё: раньше Windows выводила на экран пустое белое окно, и оно стояло так всё время сборки. Между показом и первой отрисовкой окно скрыто от экрана средством Windows (ui/window_first_frame.py), поэтому белой вспышки нет. Боковое меню целиком и поле поиска строятся до показа, заголовки групп встают на место сразу — меню больше не достраивается и не съезжает на глазах. Фоновые задачи запуска идут по одной на общей дорожке StartupLane (main/post_startup_threading.py), а не в своём потоке у каждой подсистемы: в первые полторы секунды одновременно работали пять-семь потоков и по очереди отбирали общий замок Python друг у друга и у окна. Свой поток остался только у очередей, которые ждут сеть. То, что сразу видно на главной странице (список профилей), считается первым; подсчёт частоты стратегий вынесен в отдельный прогрев в конец очереди. Скрытые страницы собираются заранее, только когда дорожка пуста и обход уже запущен. Интервал переключения замка Python для видимого окна уменьшен с 1 до 0,5 мс: Windows не ждёт меньше миллисекунды, поэтому 1 мс длился ~2 мс на каждое обращение окна к своему коду, а интервал меньше 1 мс CPython округляет до нуля. Замеры на win10 (до → после): рывки в первые полторы секунды после появления окна ~1150 мс → 96 мс; список профилей 960 → 140 мс; сборка списков адресов 1097 → 18 мс; запуск winws2 1695 → 912 мс; сборка страницы в GUI-потоке рядом с одним занятым фоновым потоком 2568 → 113 мс. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
49 lines
2.2 KiB
Python
49 lines
2.2 KiB
Python
from __future__ import annotations
|
||
|
||
import inspect
|
||
import unittest
|
||
|
||
|
||
class SidebarStartupDelayTests(unittest.TestCase):
|
||
"""Боковое меню не достраивается таймерами после показа окна.
|
||
|
||
Замер на Windows: 16 пунктов меню, пять скрытых и поле поиска строятся за
|
||
~5 мс, пока фоновые потоки молчат. Отложенные на «после показа», они
|
||
попадали на одно время с фоновыми задачами запуска и из-за общего замка
|
||
Python занимали 116 + 356 + 30 мс, а окно при этом перестраивалось на
|
||
глазах у пользователя.
|
||
"""
|
||
|
||
def test_sidebar_has_no_deferred_build_stages(self) -> None:
|
||
import ui.navigation.sidebar_builder as sidebar_builder
|
||
|
||
for name in (
|
||
"SIDEBAR_SECONDARY_GROUPS_AFTER_INTERACTIVE_MS",
|
||
"SIDEBAR_SECONDARY_GROUP_STEP_MS",
|
||
"SIDEBAR_SEARCH_AFTER_INTERACTIVE_MS",
|
||
"SIDEBAR_HIDDEN_MODE_ITEMS_AFTER_INTERACTIVE_MS",
|
||
"_schedule_sidebar_search_after_interactive",
|
||
"_schedule_secondary_sidebar_groups_after_interactive",
|
||
"_schedule_hidden_mode_nav_items_after_interactive",
|
||
"_install_secondary_sidebar_groups",
|
||
"_install_hidden_mode_nav_items",
|
||
):
|
||
self.assertFalse(hasattr(sidebar_builder, name), name)
|
||
|
||
def test_init_navigation_does_not_wait_for_interactive_signal(self) -> None:
|
||
import ui.navigation.sidebar_builder as sidebar_builder
|
||
|
||
source = inspect.getsource(sidebar_builder.init_navigation)
|
||
self.assertNotIn("startup_interactive_ready", source)
|
||
self.assertIn("_install_sidebar_search(window)", source)
|
||
|
||
def test_startup_log_contract_has_no_sidebar_after_interactive_markers(self) -> None:
|
||
from main import startup_log_contract
|
||
|
||
for marker in startup_log_contract._AFTER_INTERACTIVE_MARKERS:
|
||
self.assertNotIn("Sidebar", marker)
|
||
self.assertNotIn("HiddenModeNav", marker)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|