Files
cherrypick/benchmark_di/REPORT_v2.ru.md

9.1 KiB
Raw Permalink Blame History

Сравнительный отчет DI-бенчмарка: cherrypick vs get_it vs riverpod vs kiwi vs yx_scope

Параметры запуска

  • chainCount = 100
  • nestingDepth = 100
  • repeat = 5
  • warmup = 2

Описание сценариев

  1. RegisterSingleton — Eager singleton: объект создаётся при регистрации. Измеряет скорость поиска.
  2. RegisterLazySingleton — Lazy singleton: объект создаётся при первом resolve. Измеряет создание + кэширование.
  3. ChainSingleton — Eager цепочка зависимостей A → B → ... → N. Все объекты созданы при регистрации. Чистый lookup.
  4. ChainLazySingleton — Lazy цепочка. Полное создание графа + кэширование при первом resolve. Основная метрика честного сравнения.
  5. ChainFactoryВсе элементы цепочки — фабрики. Stateless построение графа.
  6. AsyncChain — Асинхронная цепочка (async factory). Тест async/await графа.
  7. Named — Регистрация двух биндингов с именами, разрешение по имени.
  8. Override — Регистрация биндинга/цепочки в дочернем scope.

Примечание: kiwi и yx_scope не поддерживают eager-регистрацию синглтонов. Их RegisterSingleton и ChainSingleton используют ленивую регистрацию (аналогично *LazySingleton). Результаты отмечены †.


Методология

  • Оборудование: Измерения проведены на локальной машине. Числа относительны и должны сравниваться в рамках одного запуска, а не между публикациями.
  • Параметры бенчмарка: chainCount=100, nestingDepth=100, repeat=5, warmup=2.
  • Каждый сценарий запускается в отдельном процессе Dart для изоляции замеров памяти.
  • Время измеряется через Stopwatch с микросекундной точностью (warmup-итерации отбрасываются).
  • Память измеряется через ProcessInfo.currentRss (пиковый RSS на процесс).
  • Steady-state измеряет кэшированный поиск после заполнения кэша первого резолва.

Первый резолв (среднее время, мкс)

Сценарий cherrypick get_it riverpod kiwi yx_scope
RegisterSingleton 12.8 14.6 17.6 0.4† 22.8†
RegisterLazySingleton 1.2 4.2 5.4 0.2 9.0
ChainSingleton 4.8 2.8 436.2 67.8† 134.2†
ChainLazySingleton 46.8 193.2 398.0 56.0 266.8
ChainFactory 54.0 66.0 443.0 55.6 146.6
AsyncChain 247.8 15033.0 1379.0 -- --
Named 0.2 0.6 3.4 0.2 7.8
Override 9.8 3.8 408.8 61.8 138.6

Устоявшееся состояние (steady-state, среднее время, мкс)

Сценарий cherrypick get_it riverpod kiwi yx_scope
RegisterSingleton 0.0 0.2 1.0 0.0 0.0
RegisterLazySingleton 0.0 0.0 1.0 0.0 0.0
ChainSingleton 2.8 0.8 2.8 1.6 2.0
ChainLazySingleton 1.4 1.2 1.8 1.0 1.4
ChainFactory 31.2 62.6 2.0 51.6 1.6
AsyncChain 57.2 31.6 18.2 -- --
Named 0.0 0.2 0.2 0.0 0.4
Override 1.0 1.4 1.8 290.0 1.2

Пиковое потребление памяти (Пиковый RSS, Кб)

Сценарий cherrypick get_it riverpod kiwi yx_scope
RegisterSingleton 239,568 240,128 240,592 272,016 289,936
RegisterLazySingleton 239,648 240,272 240,720 272,016 289,424
ChainSingleton 275,664 290,912 258,624 281,728 287,104
ChainLazySingleton 292,704 321,232 287,168 297,808 288,160
ChainFactory 298,848 361,264 293,968 279,792 290,768
AsyncChain 278,320 482,864 281,440 -- --
Named 272,896 482,880 279,728 272,016 287,376
Override 281,968 540,944 278,240 279,184 281,216

Стабильность (коэффициент Stddev/Mean)

Сценарий cherrypick get_it riverpod kiwi yx_scope
RegisterSingleton 1.84 1.62 1.43 1.23 1.18
RegisterLazySingleton 0.57 0.23 0.43 2.00 1.78
ChainSingleton 0.36 0.27 0.06 0.37 0.17
ChainLazySingleton 0.17 0.43 0.10 0.14 0.63
ChainFactory 0.27 0.01 0.22 0.09 0.23
AsyncChain 0.06 0.18 0.07 -- --
Named 2.00 0.67 0.15 2.00 1.74
Override 0.08 0.11 0.17 0.03 0.03

Анализ

Первый резолв — Lazy цепочка синглтонов (ChainLazySingleton)

Все DI создают полный граф зависимостей при первом резолве — единственно честное сравнение.

  • cherrypick: 46.8 мкс — в 4.1 раза быстрее get_it (193.2 мкс), в 8.5 раза быстрее riverpod (398.0 мкс)
  • kiwi: 56.0 мкс (+30% к cherrypick)
  • yx_scope: 266.8 мкс (высокая дисперсия, stddev/mean = 0.63)

Первый резолв — Eager цепочка синглтонов (ChainSingleton)

Все объекты созданы при регистрации; измеряется чистая скорость поиска. Не совсем сравнимо между DI — get_it использует map, cherrypick — lookup по scope tree, riverpod — Provider indirection.

  • get_it: 2.8 мкс (map lookup)
  • cherrypick: 5.4 мкс (scope tree lookup)
  • riverpod: 436.2 мкс (накладные расходы Provider)

Асинхронная цепочка (AsyncChain)

  • cherrypick доминирует: 247.8 мкс (vs get_it 15 033 мкс = в 61 раз быстрее)
  • riverpod: 1 379 мкс (в 6.3 раза медленнее cherrypick)
  • kiwi и yx_scope не поддерживают async

Использование памяти

  • cherrypick потребляет значительно меньше памяти чем get_it:
    • Named: 210 Мб (43%)
    • Override: 259 Мб (48%)
    • AsyncChain: 204 Мб (42%)
  • riverpod — наименьшее потребление на ChainSingleton (258 624 Кб vs 275 664 Кб у cherrypick)
  • kiwi и yx_scope — умеренное потребление памяти

Стабильность

  • cherrypick: низкая дисперсия на ChainLazySingleton (0.17) и Override (0.08)
  • get_it: наиболее стабилен на ChainFactory (0.01)
  • yx_scope: наибольшая дисперсия на ChainLazySingleton (0.63)

Рекомендации

  • cherrypick: Самый быстрый lazy резолв графов, лучшая async производительность, наименьшее потребление памяти
  • get_it: Самый быстрый eager singleton lookup; не подходит для async и глубоких lazy графов
  • kiwi: Лёгкая sync-only альтернатива; +30% на lazy цепочках vs cherrypick
  • riverpod: Сильная steady-state производительность фабрик; дорогой первый резолв на глубоких цепочках
  • yx_scope: Стабильный steady-state; ненадёжный первый резолв на глубоких lazy графах (высокая дисперсия)

_Обновлено: 26 апреля 2026.