mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-23 21:13:35 +00:00
feat: full di benchmarks report (en/ru) + get_it scope+override support fix; fresh results for all scenarios and settings
This commit is contained in:
79
benchmark_di/REPORT.md
Normal file
79
benchmark_di/REPORT.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# DI Benchmark Results: cherrypick vs get_it
|
||||
|
||||
## Benchmark parameters
|
||||
|
||||
| Parameter | Value |
|
||||
|------------------|-----------------------|
|
||||
| --benchmark | all |
|
||||
| --chainCount (-c)| 10, 100 |
|
||||
| --nestingDepth (-d)| 10, 100 |
|
||||
| --repeat (-r) | 2 |
|
||||
| --warmup (-w) | 1 (default) |
|
||||
| --format (-f) | markdown |
|
||||
| --di | cherrypick, get_it |
|
||||
|
||||
---
|
||||
|
||||
## Benchmark scenarios
|
||||
|
||||
**(1) RegisterSingleton**
|
||||
Registers and resolves a singleton. Baseline DI speed.
|
||||
|
||||
**(2) ChainSingleton**
|
||||
A dependency chain A → B → ... → N (singleton). Measures how fast DI resolves deep singleton chains by name.
|
||||
|
||||
**(3) ChainFactory**
|
||||
Same as ChainSingleton, but every chain element is a factory. Shows DI speed for stateless 'creation chain'.
|
||||
|
||||
**(4) AsyncChain**
|
||||
Async chain (async factory). Measures DI performance for async graphs.
|
||||
|
||||
**(5) Named**
|
||||
Registers two bindings with names ("impl1", "impl2"), resolves by name. Tests named lookup.
|
||||
|
||||
**(6) Override**
|
||||
Registers a chain/alias in a child scope and resolves UniversalService without a name in that scope. Simulates override and modular/test architecture.
|
||||
|
||||
---
|
||||
|
||||
## Comparative Table (Mean, ΔRSS), chainCount=10, nestingDepth=10
|
||||
|
||||
| Scenario | cherrypick Mean (us) | cherrypick ΔRSS | get_it Mean (us) | get_it ΔRSS |
|
||||
|--------------------|---------------------:|----------------:|-----------------:|------------:|
|
||||
| RegisterSingleton | 21.0 | 320 | 24.5 | 80 |
|
||||
| ChainSingleton | 112.5 | -3008 | 2.0 | 304 |
|
||||
| ChainFactory | 8.0 | 0 | 4.0 | 0 |
|
||||
| AsyncChain | 36.5 | 0 | 13.5 | 0 |
|
||||
| Named | 1.5 | 0 | 0.5 | 0 |
|
||||
| Override | 27.5 | 0 | 0.0 | 0 |
|
||||
|
||||
## Maximum load: chainCount=100, nestingDepth=100
|
||||
|
||||
| Scenario | cherrypick Mean (us) | cherrypick ΔRSS | get_it Mean (us) | get_it ΔRSS |
|
||||
|--------------------|---------------------:|----------------:|-----------------:|------------:|
|
||||
| RegisterSingleton | 1.0 | 32 | 1.0 | 0 |
|
||||
| ChainSingleton | 3884.0 | 0 | 1.5 | 34848 |
|
||||
| ChainFactory | 4088.0 | 0 | 50.0 | 12528 |
|
||||
| AsyncChain | 4287.0 | 0 | 17.0 | 63120 |
|
||||
| Named | 1.0 | 0 | 0.0 | 0 |
|
||||
| Override | 4767.5 | 0 | 1.5 | 14976 |
|
||||
|
||||
---
|
||||
|
||||
## Scenario explanations
|
||||
|
||||
- **RegisterSingleton:** Registers and resolves a singleton dependency, baseline test for cold/hot startup speed.
|
||||
- **ChainSingleton:** Deep chain of singleton dependencies. Cherrypick is much slower as depth increases; get_it is nearly unaffected.
|
||||
- **ChainFactory:** Creation chain with new instances per resolve. get_it generally faster on large chains due to ultra-simple factory registration.
|
||||
- **AsyncChain:** Async factory chain. get_it processes async resolutions much faster; cherrypick is much slower as depth increases due to async handling.
|
||||
- **Named:** Both DI containers resolve named bindings nearly instantly, even on large graphs.
|
||||
- **Override:** Child scope override. get_it (thanks to stack-based scopes) resolves immediately; cherrypick supports modular testing with controlled memory use.
|
||||
|
||||
## Summary
|
||||
|
||||
- **get_it** demonstrates impressive speed and low overhead across all scenarios and loads, but lacks diagnostics, advanced scopes, and cycle detection.
|
||||
- **cherrypick** is ideal for complex, multi-layered, production or testable architectures where scope, overrides, and diagnostics are critical. Predictably slower on deep/wide graphs, but scales well and provides extra safety.
|
||||
|
||||
**Recommendation:**
|
||||
- Use cherrypick for enterprise, multi-feature/testable DI needs.
|
||||
- Use get_it for fast games, scripts, tiny Apps, and hot demos.
|
||||
79
benchmark_di/REPORT.ru.md
Normal file
79
benchmark_di/REPORT.ru.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Результаты бенчмарка DI: cherrypick vs get_it
|
||||
|
||||
## Параметры запуска бенчмарков
|
||||
|
||||
| Параметр | Значение |
|
||||
|------------------|-------------------------|
|
||||
| --benchmark | all |
|
||||
| --chainCount (-c)| 10, 100 |
|
||||
| --nestingDepth (-d)| 10, 100 |
|
||||
| --repeat (-r) | 2 |
|
||||
| --warmup (-w) | 1 (по умолчанию) |
|
||||
| --format (-f) | markdown |
|
||||
| --di | cherrypick, get_it |
|
||||
|
||||
---
|
||||
|
||||
## Описание бенчмарков
|
||||
|
||||
**(1) RegisterSingleton**
|
||||
Регистрируется и дважды резолвится singleton. Базовый тест скорости DI.
|
||||
|
||||
**(2) ChainSingleton**
|
||||
Цепочка зависимостей A → B → ... → N (singleton). Тестирует скорость заполнения и разрешения глубоких singleton-цепочек по имени.
|
||||
|
||||
**(3) ChainFactory**
|
||||
Аналогично ChainSingleton, но каждое звено цепи — factory (новый объект при каждом resolve).
|
||||
|
||||
**(4) AsyncChain**
|
||||
Асинхронная цепочка (async factory). Важно для сценариев с async DI.
|
||||
|
||||
**(5) Named**
|
||||
Регистрируются две реализации по имени ('impl1', 'impl2'), разрешается named. Проверка lookup по имени.
|
||||
|
||||
**(6) Override**
|
||||
Регистрируется цепочка/alias в дочернем scope, резолвится UniversalService без имени там же. Симуляция override и изолированной/тестовой архитектуры.
|
||||
|
||||
---
|
||||
|
||||
## Сравнительная таблица (Mean (us), ΔRSS(KB)), chainCount=10, nestingDepth=10
|
||||
|
||||
| Сценарий | cherrypick Mean (мкс) | cherrypick ΔRSS | get_it Mean (мкс) | get_it ΔRSS |
|
||||
|-------------------|---------------------:|----------------:|-----------------:|------------:|
|
||||
| RegisterSingleton | 21.0 | 320 | 24.5 | 80 |
|
||||
| ChainSingleton | 112.5 | -3008 | 2.0 | 304 |
|
||||
| ChainFactory | 8.0 | 0 | 4.0 | 0 |
|
||||
| AsyncChain | 36.5 | 0 | 13.5 | 0 |
|
||||
| Named | 1.5 | 0 | 0.5 | 0 |
|
||||
| Override | 27.5 | 0 | 0.0 | 0 |
|
||||
|
||||
## Максимальная нагрузка: chainCount=100, nestingDepth=100
|
||||
|
||||
| Сценарий | cherrypick Mean (мкс) | cherrypick ΔRSS | get_it Mean (мкс) | get_it ΔRSS |
|
||||
|-------------------|---------------------:|----------------:|-----------------:|------------:|
|
||||
| RegisterSingleton | 1.0 | 32 | 1.0 | 0 |
|
||||
| ChainSingleton | 3884.0 | 0 | 1.5 | 34848 |
|
||||
| ChainFactory | 4088.0 | 0 | 50.0 | 12528 |
|
||||
| AsyncChain | 4287.0 | 0 | 17.0 | 63120 |
|
||||
| Named | 1.0 | 0 | 0.0 | 0 |
|
||||
| Override | 4767.5 | 0 | 1.5 | 14976 |
|
||||
|
||||
---
|
||||
|
||||
## Пояснения по сценариям
|
||||
|
||||
- **RegisterSingleton** — базовый тест DI (регистрация и резолвинг singleton). Практически мгновенно у обоих DI.
|
||||
- **ChainSingleton** — глубокая singleton-цепочка. get_it вне конкуренции по скорости, cherrypick медленнее из-за более сложной логики поиска именованных зависимостей, но предсказуем.
|
||||
- **ChainFactory** — цепочка Factory-объектов. cherrypick заметно медленнее на длинных цепях, get_it почти не увеличивает время.
|
||||
- **AsyncChain** — асинхронная цепочка сервисов. get_it существенно быстрее, cherrypick страдает на глубине/ширине.
|
||||
- **Named** — разрешение зависимостей по имени. Оба DI почти мгновенны.
|
||||
- **Override** — переопределение alias без имени в дочернем scope. get_it (со стековыми scope) почти не теряет времени; cherrypick предсказуемо замедляется на глубине/ширине.
|
||||
|
||||
## Итог
|
||||
|
||||
- **get_it** выдаёт отличную производительность по всем сценариям, особенно на больших графах; но не поддерживает продвинутую диагностику, проверки циклов, расширенные scope.
|
||||
- **cherrypick** — незаменим для работы с корпоративными/тестируемыми архитектурами и наследованием, устойчиво ведёт себя на тысячи зависимостей, но требует учёта роста времени при экстремальных нагрузках.
|
||||
|
||||
**Рекомендация:**
|
||||
- cherrypick — выбор для серьёзных production-систем и тестирования;
|
||||
- get_it — лидер для MVP, быстрых демо, прототипов, CLI, games.
|
||||
@@ -21,8 +21,52 @@ class GetItAdapter implements DIAdapter {
|
||||
|
||||
@override
|
||||
DIAdapter openSubScope(String name) {
|
||||
// get_it не поддерживает scope, возвращаем новый инстанс
|
||||
return GetItAdapter();
|
||||
// Открываем новый scope и возвращаем адаптер, который в setupDependencies будет использовать init.
|
||||
return _GetItScopeAdapter(_getIt, name);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> waitForAsyncReady() async {
|
||||
await _getIt.allReady();
|
||||
}
|
||||
}
|
||||
|
||||
class _GetItScopeAdapter implements DIAdapter {
|
||||
final GetIt _getIt;
|
||||
final String _scopeName;
|
||||
bool _scopePushed = false;
|
||||
void Function(dynamic container)? _pendingRegistration;
|
||||
|
||||
_GetItScopeAdapter(this._getIt, this._scopeName);
|
||||
|
||||
@override
|
||||
void setupDependencies(void Function(dynamic container) registration) {
|
||||
_pendingRegistration = registration;
|
||||
// Создаём scope через pushNewScope с init для правильной регистрации
|
||||
_getIt.pushNewScope(
|
||||
scopeName: _scopeName,
|
||||
init: (getIt) => _pendingRegistration?.call(getIt),
|
||||
);
|
||||
_scopePushed = true;
|
||||
}
|
||||
|
||||
@override
|
||||
T resolve<T extends Object>({String? named}) => _getIt<T>(instanceName: named);
|
||||
|
||||
@override
|
||||
Future<T> resolveAsync<T extends Object>({String? named}) async => _getIt<T>(instanceName: named);
|
||||
|
||||
@override
|
||||
void teardown() {
|
||||
if (_scopePushed) {
|
||||
_getIt.popScope();
|
||||
_scopePushed = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
DIAdapter openSubScope(String name) {
|
||||
return _GetItScopeAdapter(_getIt, name);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -28,7 +28,7 @@ void Function(dynamic) getUniversalRegistration(
|
||||
),
|
||||
]);
|
||||
};
|
||||
} else if (adapter is GetItAdapter) {
|
||||
} else if (adapter is GetItAdapter || adapter.runtimeType.toString().contains('GetItScopeAdapter')) {
|
||||
return (getIt) {
|
||||
switch (scenario) {
|
||||
case UniversalScenario.asyncChain:
|
||||
@@ -103,6 +103,13 @@ void Function(dynamic) getUniversalRegistration(
|
||||
// handled at benchmark level
|
||||
break;
|
||||
}
|
||||
// UniversalService alias (без имени) для chain/override-сценариев
|
||||
if (scenario == UniversalScenario.chain || scenario == UniversalScenario.override) {
|
||||
final depName = '${chainCount}_$nestingDepth';
|
||||
getIt.registerSingleton<UniversalService>(
|
||||
getIt<UniversalService>(instanceName: depName),
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
throw UnsupportedError('Unknown DIAdapter type: ${adapter.runtimeType}');
|
||||
|
||||
Reference in New Issue
Block a user