Окно показывается после сборки интерфейса, а не до неё: раньше 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>
107 lines
3.9 KiB
Python
107 lines
3.9 KiB
Python
from __future__ import annotations
|
|
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
from unittest.mock import Mock, patch
|
|
|
|
|
|
PROJECT_SRC = Path(__file__).resolve().parents[1] / "src"
|
|
if str(PROJECT_SRC) not in sys.path:
|
|
sys.path.insert(0, str(PROJECT_SRC))
|
|
|
|
|
|
class StartupAutostartOrderTests(unittest.TestCase):
|
|
def test_theme_and_background_steps_do_not_block_startup_autostart(self) -> None:
|
|
from main import startup_coordinator
|
|
from main.startup_coordinator import StartupCoordinator
|
|
|
|
class Runtime:
|
|
def __init__(self) -> None:
|
|
self.calls: list[str] = []
|
|
|
|
def init_launch_runtime_api(self) -> None:
|
|
self.calls.append("runtime_api")
|
|
|
|
def init_launch_runtime(self) -> None:
|
|
self.calls.append("runtime")
|
|
|
|
def init_process_monitor(self) -> None:
|
|
self.calls.append("process_monitor")
|
|
|
|
def init_core_startup(self) -> None:
|
|
self.calls.append("core_startup")
|
|
|
|
def snapshot(self):
|
|
return SimpleNamespace(launch_method="zapret2_mode")
|
|
|
|
def start_autostart(self, launch_method: str | None = None) -> None:
|
|
self.calls.append(f"autostart:{launch_method}")
|
|
|
|
runtime = Runtime()
|
|
migrate_gui_autostart = Mock(return_value=False)
|
|
coordinator = StartupCoordinator(
|
|
runtime_feature=runtime,
|
|
tray_feature=SimpleNamespace(init=Mock(), is_initialized=Mock(return_value=False)),
|
|
window_shell=SimpleNamespace(
|
|
start_in_tray=False,
|
|
set_status=Mock(),
|
|
mark_startup_core_ready=Mock(),
|
|
mark_startup_post_init_done=Mock(),
|
|
init_theme_manager=Mock(side_effect=lambda: runtime.calls.append("theme")),
|
|
),
|
|
log_startup_metric=Mock(),
|
|
migrate_gui_autostart=migrate_gui_autostart,
|
|
)
|
|
scheduled: list[tuple[int, object]] = []
|
|
background_targets: list[tuple[str, object]] = []
|
|
|
|
with (
|
|
patch.object(startup_coordinator, "run_queued", side_effect=lambda callback: scheduled.append((0, callback))),
|
|
patch.object(
|
|
startup_coordinator.QTimer,
|
|
"singleShot",
|
|
side_effect=lambda delay_ms, callback: scheduled.append((int(delay_ms), callback)),
|
|
),
|
|
patch.object(
|
|
startup_coordinator,
|
|
"start_daemon_thread",
|
|
side_effect=lambda name, target: background_targets.append((str(name), target)),
|
|
),
|
|
patch.object(
|
|
startup_coordinator,
|
|
"enqueue_subsystem_task",
|
|
side_effect=lambda _queue, name, target: background_targets.append((str(name), target)),
|
|
),
|
|
):
|
|
coordinator.run_async_init()
|
|
while scheduled:
|
|
_delay_ms, callback = scheduled.pop(0)
|
|
callback()
|
|
|
|
self.assertEqual(
|
|
runtime.calls,
|
|
["runtime_api", "runtime", "autostart:zapret2_mode", "theme", "process_monitor"],
|
|
)
|
|
|
|
targets_by_name = dict(background_targets)
|
|
self.assertEqual(
|
|
set(targets_by_name),
|
|
{"GuiAutostartMigration", "StartupStep-core_startup"},
|
|
)
|
|
targets_by_name["GuiAutostartMigration"]()
|
|
migrate_gui_autostart.assert_called_once_with()
|
|
targets_by_name["StartupStep-core_startup"]()
|
|
while scheduled:
|
|
_delay_ms, callback = scheduled.pop(0)
|
|
callback()
|
|
|
|
self.assertEqual(
|
|
runtime.calls,
|
|
["runtime_api", "runtime", "autostart:zapret2_mode", "theme", "process_monitor", "core_startup"],
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|