|
| 1 | +# Resolution Pipeline |
| 2 | + |
| 3 | +- [Resolution Pipeline](#resolution-pipeline) |
| 4 | + - [Overview](#overview) |
| 5 | + - [Relative Performance](#relative-performance) |
| 6 | + - [Rules.WithUseInterpretation](#ruleswithuseinterpretation) |
| 7 | + - [Rules.WithoutUseInterpretationForFirstResolution](#ruleswithoutuseinterpretationforfirstresolution) |
| 8 | + - [Rules.WithoutFastExpressionCompiler](#ruleswithoutfastexpressioncompiler) |
| 9 | + |
| 10 | +## Overview |
| 11 | + |
| 12 | +What happens when you call `container.Resolve<X>();` for the same service `X` multiple times in a sequence assuming that the `X` is not a singleton*: |
| 13 | + |
| 14 | +1. The first call will **discover and construct the expression tree** of `X` object graph, **interpret** the expression to get the service, and if succeeded will **cache the expression** in resolution cache. |
| 15 | +2. The second call will find cached expression, will **compile** it to delegate, then it will **replace the cached expression with the delegate** and will invoke the delegate to get the service. |
| 16 | +3. The third call will find the cached delegate and invoke it. |
| 17 | + |
| 18 | +singleton* - those are always interpreted (cannot be changed via rules) and injected in object graph as `ConstantExpression` unless wrapped in Func or Lazy wrappers (which create singleton when consumer demand). |
| 19 | +This is because they need to be created once and one-time interpretation is faster than compilation+invocation. |
| 20 | + |
| 21 | + |
| 22 | +## Relative Performance |
| 23 | + |
| 24 | +- Expression interpretation is 10x times slower than the delegate invocation |
| 25 | +- Delegate compilation is 100x slower than interpretation. |
| 26 | + |
| 27 | +Now, spot the problem for the multi-threaded resolution of the same service (#208) |
| 28 | + |
| 29 | +## Rules.WithUseInterpretation |
| 30 | + |
| 31 | +The compilation (essentially `System.Reflection.Emit`) is not supported by all targets, e.g. Xamarin iOS. In this case, you may specify to always use interpretation via |
| 32 | + |
| 33 | +```cs |
| 34 | +var c = new Container(rules => rules.WithUseInterpretation()); |
| 35 | +``` |
| 36 | + |
| 37 | +DryIoc uses its own interpretation mechanism which is faster than `System.Linq.Expressions.Expression.Compile(preferInterpretation: true)` because DryIoc can recognize its own internal methods in the resolved expression tree, and call them directly without reflection. It has other optimizations as well. |
| 38 | + |
| 39 | +## Rules.WithoutUseInterpretationForFirstResolution |
| 40 | + |
| 41 | +On the contrary, if you want to Compile on the first resolution, maybe to "warm-up" the container before the actual usage you can do that via |
| 42 | + |
| 43 | +```cs |
| 44 | +var c = new Container(rules => rules.WithoutUseInterpretationForFirstResolution()); |
| 45 | +``` |
| 46 | + |
| 47 | +## Rules.WithoutFastExpressionCompiler |
| 48 | + |
| 49 | +By default, DryIoc relies on [its own Expression Tree compiler](https://github.com/dadhi/FastExpressionCompiler). But it doesn't support certain old platforms, e.g. PCL, <= .NET 4.0, <= .NET Standard 1.2 - so the default `Expression.Compile` is used for them. If you want for some reason to fully switch to `Expression.Compile` you may do so via: |
| 50 | + |
| 51 | +```cs |
| 52 | +var c = new Container(rules => rules.WithoutFastExpressionCompiler()); |
| 53 | +``` |
| 54 | + |
| 55 | +But I would not recommend using it, maybe just for the last resort troubleshooting only. |
| 56 | +It is very likely that the option will be removed in future DryIoc versions. |
0 commit comments