Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance Improvements Suggestion: Avoid locks for Singletons and for RootScope #169

Open
rafaelsc opened this issue Jan 18, 2024 · 4 comments

Comments

@rafaelsc
Copy link

Currently, Jab uses locks to guarantee Singleton is only created one time.

But alternative Lazy<T> is a faster alternative to lock.

Instead of

 private Jab.Performance.Basic.Singleton.Singleton1? _ISingleton1;
 
 Jab.Performance.Basic.Singleton.ISingleton1 IServiceProvider<Jab.Performance.Basic.Singleton.ISingleton1>.GetService()
 {
     if (_ISingleton1 == null)
     lock (this)
     if (_ISingleton1 == null){
         _ISingleton1 = new Jab.Performance.Basic.Singleton.Singleton1();
     }
     return _ISingleton1;
 }

The JAB uses this code

 public ImprovedContainerSingleton()
 {
     _ISingleton1 = new(() => new Jab.Performance.Basic.Singleton.Singleton1());
 }

 private Lazy<Jab.Performance.Basic.Singleton.Singleton1> _ISingleton1;

 Jab.Performance.Basic.Singleton.ISingleton1 IServiceProvider<Jab.Performance.Basic.Singleton.ISingleton1>.GetService() => _ISingleton1.Value;

We can see up to 35% of performance improvements.

Method NumbersOfCalls NumbersOfClasses Mean Error StdDev Ratio RatioSD
Jab 1 1 3.190 ns 0.3329 ns 0.0182 ns 1.00 0.00
Improved_Jab 1 1 1.968 ns 0.1505 ns 0.0082 ns 0.62 0.00
MEDI 1 1 9.357 ns 0.2965 ns 0.0163 ns 2.93 0.02
Jab 100 3 693.577 ns 30.0415 ns 1.6467 ns 1.00 0.00
Improved_Jab 100 3 548.498 ns 7.3230 ns 0.4014 ns 0.79 0.00
MEDI 100 3 2,909.288 ns 33.8740 ns 1.8567 ns 4.19 0.01

See Details: Jab.Performance.Basic.Singleton.BasicSingletonBenchmark-report-github.md

@pakrym
Copy link
Owner

pakrym commented Jan 21, 2024

The problem with Lazy is that all instances need to be eagerly initialized on container creation, leading to a very high startup cost especially for large container.

Maybe LazyInitializer.EnsureInitialized is the way to go here.

@rafaelsc
Copy link
Author

This is the Startup benchmark for the code above. (From PR #168)

Method Mean Error StdDev Gen0 Gen1 Allocated Alloc Ratio
Jab_Singleton 9.048 ns 4.151 ns 0.2275 ns 0.0067 - 56 B 1.00
Improved_Jab_Singleton 47.049 ns 6.874 ns 0.3768 ns 0.0488 0.0001 408 B ?
MEDI_Singleton 1,927.726 ns 2,530.384 ns 138.6989 ns 0.8640 0.2155 7232 B ?

You are right, this change will cause a bigger startup timer and more allocation.

@rafaelsc
Copy link
Author

Benchmark when using LazyInitializer.EnsureInitialized

Singleton benchmark

Method NumbersOfCalls NumbersOfClasses Mean Error StdDev Ratio RatioSD
Jab 1 1 3.437 ns 3.4240 ns 0.1877 ns 1.00 0.00
Improved_Jab 1 1 1.833 ns 0.4405 ns 0.0241 ns 0.53 0.04
Improved2_Jab 1 1 2.131 ns 3.3616 ns 0.1843 ns 0.62 0.09
MEDI 1 1 9.669 ns 6.6185 ns 0.3628 ns 2.82 0.18
Jab 100 3 689.601 ns 2.0599 ns 0.1129 ns 1.00 0.00
Improved_Jab 100 3 628.522 ns 1,178.7369 ns 64.6105 ns 0.91 0.09
Improved2_Jab 100 3 590.958 ns 1,019.3358 ns 55.8732 ns 0.86 0.08
MEDI 100 3 2,935.810 ns 1,653.3193 ns 90.6240 ns 4.26 0.13

Startup benchmark

Method Mean Error StdDev Gen0 Gen1 Allocated Alloc Ratio
Jab_Singleton 9.702 ns 7.7862 ns 0.4268 ns 0.0067 - 56 B 1.00
Improved_Jab_Singleton 55.588 ns 76.3415 ns 4.1845 ns 0.0488 0.0001 408 B ?
Improved_2_Jab_Singleton 8.722 ns 0.1648 ns 0.0090 ns 0.0067 - 56 B ?
MEDI_Singleton 2,197.545 ns 1,339.7199 ns 73.4346 ns 0.8640 0.2155 7232 B ?

Code

private Jab.Performance.Basic.Singleton.Singleton1? _ISingleton1;

Jab.Performance.Basic.Singleton.ISingleton1 IServiceProvider<Jab.Performance.Basic.Singleton.ISingleton1>.GetService() => LazyInitializer.EnsureInitialized<Jab.Performance.Basic.Singleton.Singleton1>(ref this._ISingleton1);

@rafaelsc
Copy link
Author

See: #168 (comment)

@rafaelsc rafaelsc changed the title Performance Improvements for Singletons Performance Improvements Suggestion: Avoid locks for Singletons and for RootScope Jan 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants