diff --git a/Examples/BasicsAndExtensions/Program.cs b/Examples/BasicsAndExtensions/Program.cs index 11e56e09..c02bc0bd 100644 --- a/Examples/BasicsAndExtensions/Program.cs +++ b/Examples/BasicsAndExtensions/Program.cs @@ -914,22 +914,63 @@ static void ConsoleWrite(ReadOnlySpan readOnlySpan) } #endregion - #region SLazy + #region SLazy + ValueLazy { Console.WriteLine(" SLazy----------------------"); Console.WriteLine(); - Console.WriteLine(@" SLazy is a struct alternative to Lazy with some"); - Console.WriteLine(@" minor differences to: ToString, Equals, GetHashCode, and"); - Console.WriteLine(@" default constructor. There are benchmarks included in"); - Console.WriteLine(@" Towel's documentation."); + Console.WriteLine(@" SLazy is a faster Lazy when using the default"); + Console.WriteLine(@" LazyThreadSafetyMode.ExecutionAndPublication setting."); Console.WriteLine(); SLazy slazy = new(() => "hello world"); - Console.WriteLine(@$" SLazy slazy = new(() => ""hello world"");"); - Console.WriteLine(@$" slazy.IsValueCreated: {slazy.IsValueCreated}"); - Console.WriteLine(@$" slazy.Value: {slazy.Value}"); - Console.WriteLine(@$" slazy.IsValueCreated: {slazy.IsValueCreated}"); + Console.WriteLine(@$" SLazy slazy = new(() => ""hello world"");"); + Console.WriteLine(@$" slazy.IsValueCreated: {slazy.IsValueCreated}"); + Console.WriteLine(@$" slazy.Value: {slazy.Value}"); + Console.WriteLine(@$" slazy.IsValueCreated: {slazy.IsValueCreated}"); + Console.WriteLine(); + + Console.WriteLine(@$" ValueLazy is even faster than SLazy but it"); + Console.WriteLine(@$" is unsafe as it will potentially call the factory"); + Console.WriteLine(@$" delegate multiple times if the struct is copied."); + Console.WriteLine(@$" So please use ValueLazy with caution."); + Console.WriteLine(); + + ValueLazy valueLazy = new(() => "hello world"); + + Console.WriteLine(@$" ValueLazy valueLazy = new(() => ""hello world"");"); + Console.WriteLine(@$" valueLazy.IsValueCreated: {valueLazy.IsValueCreated}"); + Console.WriteLine(@$" valueLazy.Value: {valueLazy.Value}"); + Console.WriteLine(@$" valueLazy.IsValueCreated: {valueLazy.IsValueCreated}"); + Console.WriteLine(); + + Console.WriteLine(@$" Here is the main different between SLazy and ValueLazy:"); + Console.WriteLine(); + + int sLazyCount = 0; + SLazy sLazy1 = new(() => ++sLazyCount); + SLazy sLazy2 = sLazy1; + Console.WriteLine(@$" int sLazyCount = 0;"); + Console.WriteLine(@$" SLazy sLazy1 = new(() => ++sLazyCount);"); + Console.WriteLine(@$" SLazy sLazy2 = sLazy1;"); + Console.WriteLine(@$" Console.WriteLine(sLazy1.Value); -> {sLazy1.Value}"); + Console.WriteLine(@$" Console.WriteLine(sLazy2.Value); -> {sLazy2.Value}"); + Console.WriteLine(); + + int valueLazyCount = 0; + ValueLazy valueLazy1 = new(() => ++valueLazyCount); + ValueLazy valueLazy2 = valueLazy1; + Console.WriteLine(@$" int valueLazyCount = 0;"); + Console.WriteLine(@$" ValueLazy valueLazy1 = new(() => ++valueLazyCount);"); + Console.WriteLine(@$" ValueLazy valueLazy2 = valueLazy1;"); + Console.WriteLine(@$" Console.WriteLine(valueLazy1.Value); -> {valueLazy1.Value}"); + Console.WriteLine(@$" Console.WriteLine(valueLazy2.Value); -> {valueLazy2.Value}"); + Console.WriteLine(); + + Console.WriteLine(@$" Because the ValueLazy was copied, it called the factory delegate"); + Console.WriteLine(@$" multiple times. That is why SLazy is safe to use but you need to"); + Console.WriteLine(@$" be careful when using ValueLazy."); + Pause(); } #endregion diff --git a/README.md b/README.md index 23fdedca..ca6cacbb 100644 --- a/README.md +++ b/README.md @@ -925,7 +925,7 @@ Console.WriteLine("Value: " + Value); public class MyClass { } ``` -## SLazy<T> +## SLazy<T> + ValueLazy<T> ```cs // SLazy is a faster Lazy when using the default @@ -935,6 +935,11 @@ SLazy slazy = new(() => "hello world"); Console.WriteLine(slazy.IsValueCreated); // False Console.WriteLine(slazy.Value); // hello world Console.WriteLine(slazy.IsValueCreated); // True + +// ValueLazy is even faster than SLazy but it +// is unsafe as it will potentially call the factory +// delegate multiple times if the struct is copied. +// So please use ValueLazy with caution. ``` > [Initialization Benchmarks](https://zacharypatten.github.io/Towel/benchmarks/SLazyInitializationBenchmarks.html)
diff --git a/Sources/Towel/ValueLazy.cs b/Sources/Towel/ValueLazy.cs new file mode 100644 index 00000000..25b6478d --- /dev/null +++ b/Sources/Towel/ValueLazy.cs @@ -0,0 +1,96 @@ +using System; + +namespace Towel +{ + /// Provides support for lazy initialization. + /// The type of value that is being lazily initialized. + public struct ValueLazy + { + internal Func? _func; + internal T? _value; + + /// True if has been initialized. + public bool IsValueCreated => _func is null; + + /// Gets the lazily initialized value. + public T Value => _func is null ? _value! : SafeGetValue(); + + internal T SafeGetValue() + { + Func? func = _func; + if (func is not null) + { + lock (func) + { + if (_func is not null) + { + try + { + _value = _func(); + _func = null; + } + catch (Exception exception) + { + _func = () => throw exception; + throw; + } + } + } + } + return _value!; + } + + /// Constructs a new from a . + /// The value to initialize with. + public ValueLazy(T value) + { + _func = null; + _value = value; + } + + /// Constructs a new from a . + /// The method used to initialize . + /// Thrown when is null. + public ValueLazy(Func func) + { + if (func is null) throw new ArgumentNullException(nameof(func)); + _value = default; + _func = func; + } + + /// Constructs a new from a . + /// The method used to initialize . + /// Thrown when is null. + public static implicit operator ValueLazy(Func func) => new(func); + + /// Constructs a new from a . + /// The value to initialize with. + public static implicit operator ValueLazy(T value) => new(value); + + /// Checks for equality between and . + /// The value to compare to . + /// True if and are equal or False if not. + public override bool Equals(object? obj) + { + if (obj is ValueLazy slazy) + { + obj = slazy.Value; + } + return (Value, obj) switch + { + (null, null) => true, + (_, null) => false, + (null, _) => false, + _ => Value!.Equals(obj), + }; + } + + /// Returns a string that represents . + /// A string that represents + public override string? ToString() => Value?.ToString(); + + /// Gets the hash code of . + /// The hash code of . + public override int GetHashCode() => Value?.GetHashCode() ?? default; + } +} diff --git a/Tools/Towel_Benchmarking/SLazyBenchmarks.cs b/Tools/Towel_Benchmarking/SLazyBenchmarks.cs index 7c437683..0ad990fa 100644 --- a/Tools/Towel_Benchmarking/SLazyBenchmarks.cs +++ b/Tools/Towel_Benchmarking/SLazyBenchmarks.cs @@ -12,6 +12,7 @@ public class SLazyInitializationBenchmarks private Lazy[]? lazys; private Lazy[]? lazysExecutionAndPublication; private SLazy[]? slazys; + private ValueLazy[]? valueLazys; [Params(1, 10, 100, 1000, 10000)] public int N; @@ -38,6 +39,12 @@ public void IterationSetup() { slazys[i] = new(() => i); } + + valueLazys = new ValueLazy[N]; + for (int i = 0; i < N; i++) + { + valueLazys[i] = new(() => i); + } } [GlobalCleanup] @@ -72,6 +79,15 @@ public void SLazy() temp = slazys![i].Value; } } + + [Benchmark] + public void ValueLazy() + { + for (int i = 0; i < N; i++) + { + temp = valueLazys![i].Value; + } + } } [Tag(Program.Name, "SLazy Caching")] @@ -118,6 +134,16 @@ public void SLazy() temp = value.Value; } } + + [Benchmark] + public void ValueLazy() + { + ValueLazy value = new(() => -1); + for (int i = 0; i < N; i++) + { + temp = value.Value; + } + } } [Tag(Program.Name, "SLazy Construction")] @@ -154,5 +180,14 @@ public void SLazy() _ = new SLazy(() => i); } } + + [Benchmark] + public void ValueLazy() + { + for (int i = 0; i < N; i++) + { + _ = new ValueLazy(() => i); + } + } } } diff --git a/Tools/Towel_Testing/SLazy.cs b/Tools/Towel_Testing/SLazy.cs index c928dd8b..4a2328c3 100644 --- a/Tools/Towel_Testing/SLazy.cs +++ b/Tools/Towel_Testing/SLazy.cs @@ -6,7 +6,7 @@ namespace Towel_Testing { [TestClass] - public class Slazy_Testing + public class SLazy_Testing { [TestMethod] public void Testing() diff --git a/Tools/Towel_Testing/ValueLazy.cs b/Tools/Towel_Testing/ValueLazy.cs new file mode 100644 index 00000000..eae7581c --- /dev/null +++ b/Tools/Towel_Testing/ValueLazy.cs @@ -0,0 +1,190 @@ +using System; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Towel; + +namespace Towel_Testing +{ + [TestClass] + public class ValueLazy_Testing + { + [TestMethod] + public void Testing() + { + { + Assert.ThrowsException(() => new ValueLazy(default(Func)!)); + } + { + ValueLazy a = new(() => null); + Assert.IsTrue(!a.IsValueCreated); + } + { + ValueLazy a = new(() => null); + Assert.IsTrue(!a.Equals("not null")); + } + { + ValueLazy a = new(() => "not null"); + Assert.IsTrue(!a.Equals(null)); + } + { + ValueLazy a = 1; + ValueLazy b = 1; + Assert.IsTrue(a.Equals(b)); + } + { + ValueLazy a = "hello world"; + ValueLazy b = "hello world"; + Assert.IsTrue(a.Equals(b)); + } + { + ValueLazy a = "hello world"; + ValueLazy b = a; + Assert.IsTrue(a.Equals(b)); + } + { + ValueLazy a = default(string); + ValueLazy b = default(string); + Assert.IsTrue(a.Equals(b)); + } + { + ValueLazy a = 1; + Assert.IsTrue(a.Equals(a)); + } + { + ValueLazy a = "hello world"; + Assert.IsTrue(a.Equals(a)); + } + { + ValueLazy a = new(() => new()); + ValueLazy b = new(() => new()); + Assert.IsFalse(a.Equals(b)); + } + { + ValueLazy a = 1; + Assert.IsTrue(a.Equals(1)); + } + { + ValueLazy a = "hello world"; + Assert.IsTrue(a.Equals("hello world")); + } + { + ValueLazy a = default(string); + Assert.IsTrue(a.Equals(null)); + } + { + ValueLazy a = new Func(() => 1); + Assert.IsTrue(a.Equals(a)); + } + { + int value = 1; + bool ready = false; + bool thread1Ready = false; + bool thread2Ready = false; + ValueLazy slazy = new(() => + { + while (!ready) + { + default(SpinWait).SpinOnce(); + } + return ++value; + }); + Thread thread1 = new(() => { thread1Ready = true; _ = slazy.Value; }); + Thread thread2 = new(() => { thread2Ready = true; _ = slazy.Value; }); + thread1.Start(); + thread2.Start(); + SpinWait.SpinUntil(() => thread1Ready && thread2Ready); + + // just some extra waits for good measure to try to ensure + // thread1 and thread2 reach "_ = slazy.Value" + default(SpinWait).SpinOnce(); + default(SpinWait).SpinOnce(); + default(SpinWait).SpinOnce(); + + Assert.IsTrue(!slazy.IsValueCreated); + ready = true; + thread1.Join(); + thread2.Join(); + Assert.IsTrue(slazy.Value is 2); + Assert.IsTrue(value is 2); + } + { + int test = 1; + ValueLazy a = new(() => { test++; throw new Exception("Expected"); }); + Assert.IsTrue(test is 1); + Assert.ThrowsException(() => _ = a.Value); + Assert.IsTrue(test is 2); + Assert.ThrowsException(() => _ = a.Value); + Assert.IsTrue(test is 2); + Assert.ThrowsException(() => _ = a.Value); + Assert.IsTrue(test is 2); + Assert.ThrowsException(() => _ = a.Value); + } + } + + [TestMethod] + public void ToString_Testing() + { + { + ValueLazy a = default(string); + Assert.IsTrue(a.GetHashCode() is default(int)); + } + { + ValueLazy a = new(() => null); + Assert.IsTrue(a.ToString() is null); + } + { + ValueLazy a = new(() => 1); + Assert.IsTrue(a.ToString() == 1.ToString()); + } + { + ValueLazy a = new(() => "hello world"); + Assert.IsTrue(a.ToString() is "hello world"); + } + { + ValueLazy a = new(() => 1); + Assert.IsTrue(a.Value is 1); + Assert.IsTrue(a.IsValueCreated); + Assert.IsTrue(a.ToString() == 1.ToString()); + } + { + ValueLazy a = new(() => "hello world"); + Assert.IsTrue(a.Value is "hello world"); + Assert.IsTrue(a.IsValueCreated); + Assert.IsTrue(a.ToString() is "hello world"); + } + } + + [TestMethod] + public void GetHashCode_Testing() + { + { + ValueLazy a = default(object); + Assert.IsTrue(a.GetHashCode() is default(int)); + } + { + ValueLazy a = new(() => null); + Assert.IsTrue(a.GetHashCode() is default(int)); + } + { + ValueLazy a = new(() => 1); + Assert.IsTrue(a.GetHashCode() == 1.GetHashCode()); + } + { + ValueLazy a = new(() => "hello world"); + Assert.IsTrue(a.GetHashCode() == "hello world".GetHashCode()); + } + { + ValueLazy a = new(() => 1); + Assert.IsTrue(a.Value is 1); + Assert.IsTrue(a.IsValueCreated); + Assert.IsTrue(a.GetHashCode() == 1.GetHashCode()); + } + { + ValueLazy a = new(() => "hello world"); + Assert.IsTrue(a.Value is "hello world"); + Assert.IsTrue(a.IsValueCreated); + Assert.IsTrue(a.GetHashCode() == "hello world".GetHashCode()); + } + } + } +} diff --git a/Tools/docfx_project/benchmarks/SLazyCachingBenchmarks.md b/Tools/docfx_project/benchmarks/SLazyCachingBenchmarks.md index c0ae20cc..88c59afb 100644 --- a/Tools/docfx_project/benchmarks/SLazyCachingBenchmarks.md +++ b/Tools/docfx_project/benchmarks/SLazyCachingBenchmarks.md @@ -14,21 +14,25 @@ Intel Core i7-4790K CPU 4.00GHz (Haswell), 1 CPU, 8 logical and 4 physical cores ``` -| Method | N | Mean | Error | StdDev | Median | Ratio | RatioSD | -|---------------------------- |----- |----------:|---------:|---------:|----------:|------:|--------:| -| **Lazy** | **1** | **32.00 ns** | **0.655 ns** | **1.058 ns** | **31.46 ns** | **1.00** | **0.00** | -| LazyExecutionAndPublication | 1 | 30.76 ns | 0.362 ns | 0.339 ns | 30.63 ns | 0.97 | 0.03 | -| SLazy | 1 | 25.74 ns | 0.163 ns | 0.152 ns | 25.74 ns | 0.81 | 0.03 | -| | | | | | | | | -| **Lazy** | **10** | **36.97 ns** | **0.755 ns** | **0.981 ns** | **36.74 ns** | **1.00** | **0.00** | -| LazyExecutionAndPublication | 10 | 38.74 ns | 0.802 ns | 1.842 ns | 38.45 ns | 1.07 | 0.05 | -| SLazy | 10 | 30.47 ns | 0.607 ns | 0.890 ns | 30.48 ns | 0.83 | 0.03 | -| | | | | | | | | -| **Lazy** | **100** | **93.79 ns** | **1.500 ns** | **1.403 ns** | **93.76 ns** | **1.00** | **0.00** | -| LazyExecutionAndPublication | 100 | 91.69 ns | 1.021 ns | 0.905 ns | 91.61 ns | 0.98 | 0.02 | -| SLazy | 100 | 81.08 ns | 0.506 ns | 0.473 ns | 80.92 ns | 0.86 | 0.02 | -| | | | | | | | | -| **Lazy** | **1000** | **556.80 ns** | **5.807 ns** | **5.147 ns** | **555.27 ns** | **1.00** | **0.00** | -| LazyExecutionAndPublication | 1000 | 543.50 ns | 4.022 ns | 3.762 ns | 542.86 ns | 0.98 | 0.01 | -| SLazy | 1000 | 526.17 ns | 1.857 ns | 1.737 ns | 526.79 ns | 0.94 | 0.01 | +| Method | N | Mean | Error | StdDev | Ratio | RatioSD | +|---------------------------- |----- |----------:|---------:|---------:|------:|--------:| +| **Lazy** | **1** | **30.92 ns** | **0.632 ns** | **0.907 ns** | **1.00** | **0.00** | +| LazyExecutionAndPublication | 1 | 30.79 ns | 0.640 ns | 0.500 ns | 0.99 | 0.04 | +| SLazy | 1 | 24.99 ns | 0.524 ns | 0.751 ns | 0.81 | 0.03 | +| ValueLazy | 1 | 19.93 ns | 0.314 ns | 0.336 ns | 0.64 | 0.02 | +| | | | | | | | +| **Lazy** | **10** | **36.36 ns** | **0.754 ns** | **1.082 ns** | **1.00** | **0.00** | +| LazyExecutionAndPublication | 10 | 35.81 ns | 0.446 ns | 0.373 ns | 0.99 | 0.03 | +| SLazy | 10 | 29.72 ns | 0.415 ns | 0.368 ns | 0.82 | 0.02 | +| ValueLazy | 10 | 25.96 ns | 0.517 ns | 0.531 ns | 0.72 | 0.03 | +| | | | | | | | +| **Lazy** | **100** | **92.71 ns** | **1.697 ns** | **1.587 ns** | **1.00** | **0.00** | +| LazyExecutionAndPublication | 100 | 91.83 ns | 1.016 ns | 0.849 ns | 0.99 | 0.02 | +| SLazy | 100 | 79.19 ns | 0.906 ns | 0.848 ns | 0.85 | 0.02 | +| ValueLazy | 100 | 73.69 ns | 0.896 ns | 0.795 ns | 0.80 | 0.02 | +| | | | | | | | +| **Lazy** | **1000** | **536.37 ns** | **5.678 ns** | **5.312 ns** | **1.00** | **0.00** | +| LazyExecutionAndPublication | 1000 | 535.64 ns | 2.491 ns | 2.331 ns | 1.00 | 0.01 | +| SLazy | 1000 | 529.02 ns | 5.518 ns | 4.892 ns | 0.99 | 0.01 | +| ValueLazy | 1000 | 520.57 ns | 6.519 ns | 5.090 ns | 0.97 | 0.01 | diff --git a/Tools/docfx_project/benchmarks/SLazyConstructionBenchmarks.md b/Tools/docfx_project/benchmarks/SLazyConstructionBenchmarks.md index c6e66973..b41255cf 100644 --- a/Tools/docfx_project/benchmarks/SLazyConstructionBenchmarks.md +++ b/Tools/docfx_project/benchmarks/SLazyConstructionBenchmarks.md @@ -14,25 +14,30 @@ Intel Core i7-4790K CPU 4.00GHz (Haswell), 1 CPU, 8 logical and 4 physical cores ``` -| Method | N | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | -|---------------------------- |------ |--------------:|-------------:|--------------:|--------------:|------:|--------:|---------:|------:|------:|------------:| -| **Lazy** | **1** | **22.50 ns** | **0.449 ns** | **0.763 ns** | **22.16 ns** | **1.00** | **0.00** | **0.0382** | **-** | **-** | **160 B** | -| LazyExecutionAndPublication | 1 | 22.22 ns | 0.466 ns | 0.536 ns | 22.11 ns | 0.97 | 0.05 | 0.0382 | - | - | 160 B | -| SLazy | 1 | 16.22 ns | 0.137 ns | 0.114 ns | 16.23 ns | 0.70 | 0.02 | 0.0287 | - | - | 120 B | -| | | | | | | | | | | | | -| **Lazy** | **10** | **202.49 ns** | **3.694 ns** | **3.628 ns** | **200.95 ns** | **1.00** | **0.00** | **0.3309** | **-** | **-** | **1,384 B** | -| LazyExecutionAndPublication | 10 | 201.18 ns | 1.589 ns | 1.487 ns | 201.02 ns | 0.99 | 0.02 | 0.3309 | - | - | 1,384 B | -| SLazy | 10 | 143.28 ns | 2.875 ns | 2.824 ns | 142.50 ns | 0.71 | 0.02 | 0.2351 | - | - | 984 B | -| | | | | | | | | | | | | -| **Lazy** | **100** | **2,012.92 ns** | **30.173 ns** | **34.747 ns** | **2,003.43 ns** | **1.00** | **0.00** | **3.2539** | **-** | **-** | **13,624 B** | -| LazyExecutionAndPublication | 100 | 2,034.90 ns | 35.676 ns | 42.469 ns | 2,024.93 ns | 1.01 | 0.03 | 3.2539 | - | - | 13,624 B | -| SLazy | 100 | 1,360.76 ns | 25.861 ns | 21.595 ns | 1,359.66 ns | 0.67 | 0.02 | 2.3003 | - | - | 9,624 B | -| | | | | | | | | | | | | -| **Lazy** | **1000** | **19,391.63 ns** | **195.598 ns** | **163.333 ns** | **19,312.63 ns** | **1.00** | **0.00** | **32.5012** | **-** | **-** | **136,024 B** | -| LazyExecutionAndPublication | 1000 | 21,608.07 ns | 308.875 ns | 288.922 ns | 21,617.02 ns | 1.11 | 0.01 | 32.5012 | - | - | 136,024 B | -| SLazy | 1000 | 13,113.88 ns | 200.511 ns | 167.436 ns | 13,089.79 ns | 0.68 | 0.01 | 22.9492 | - | - | 96,024 B | -| | | | | | | | | | | | | -| **Lazy** | **10000** | **201,931.58 ns** | **4,956.269 ns** | **14,140.514 ns** | **195,520.00 ns** | **1.00** | **0.00** | **325.1953** | **-** | **-** | **1,360,024 B** | -| LazyExecutionAndPublication | 10000 | 200,473.35 ns | 1,523.730 ns | 1,189.628 ns | 200,682.32 ns | 0.98 | 0.07 | 325.1953 | - | - | 1,360,024 B | -| SLazy | 10000 | 136,375.92 ns | 2,699.036 ns | 6,092.175 ns | 133,926.17 ns | 0.67 | 0.05 | 229.4922 | - | - | 960,024 B | +| Method | N | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | +|---------------------------- |------ |--------------:|-------------:|-------------:|------:|--------:|---------:|------:|------:|------------:| +| **Lazy** | **1** | **21.62 ns** | **0.443 ns** | **0.415 ns** | **1.00** | **0.00** | **0.0382** | **-** | **-** | **160 B** | +| LazyExecutionAndPublication | 1 | 21.11 ns | 0.314 ns | 0.262 ns | 0.98 | 0.02 | 0.0382 | - | - | 160 B | +| SLazy | 1 | 15.93 ns | 0.157 ns | 0.139 ns | 0.74 | 0.02 | 0.0287 | - | - | 120 B | +| ValueLazy | 1 | 11.91 ns | 0.266 ns | 0.544 ns | 0.54 | 0.02 | 0.0210 | - | - | 88 B | +| | | | | | | | | | | | +| **Lazy** | **10** | **192.09 ns** | **2.707 ns** | **2.532 ns** | **1.00** | **0.00** | **0.3309** | **-** | **-** | **1,384 B** | +| LazyExecutionAndPublication | 10 | 199.57 ns | 3.994 ns | 5.855 ns | 1.04 | 0.04 | 0.3309 | - | - | 1,384 B | +| SLazy | 10 | 140.37 ns | 2.527 ns | 2.364 ns | 0.73 | 0.01 | 0.2351 | - | - | 984 B | +| ValueLazy | 10 | 94.04 ns | 1.169 ns | 1.094 ns | 0.49 | 0.01 | 0.1587 | - | - | 664 B | +| | | | | | | | | | | | +| **Lazy** | **100** | **1,910.85 ns** | **12.321 ns** | **11.525 ns** | **1.00** | **0.00** | **3.2539** | **-** | **-** | **13,624 B** | +| LazyExecutionAndPublication | 100 | 1,897.59 ns | 37.460 ns | 52.513 ns | 0.99 | 0.04 | 3.2558 | - | - | 13,624 B | +| SLazy | 100 | 1,314.51 ns | 25.721 ns | 24.060 ns | 0.69 | 0.01 | 2.3003 | - | - | 9,624 B | +| ValueLazy | 100 | 858.02 ns | 13.774 ns | 11.502 ns | 0.45 | 0.01 | 1.5354 | - | - | 6,424 B | +| | | | | | | | | | | | +| **Lazy** | **1000** | **19,371.04 ns** | **381.131 ns** | **423.627 ns** | **1.00** | **0.00** | **32.5012** | **-** | **-** | **136,024 B** | +| LazyExecutionAndPublication | 1000 | 19,359.57 ns | 327.790 ns | 414.549 ns | 1.00 | 0.02 | 32.5012 | - | - | 136,024 B | +| SLazy | 1000 | 13,613.61 ns | 134.713 ns | 112.492 ns | 0.70 | 0.02 | 22.9492 | - | - | 96,024 B | +| ValueLazy | 1000 | 8,841.21 ns | 175.317 ns | 392.122 ns | 0.45 | 0.02 | 15.3046 | - | - | 64,024 B | +| | | | | | | | | | | | +| **Lazy** | **10000** | **182,700.92 ns** | **2,167.632 ns** | **1,921.550 ns** | **1.00** | **0.00** | **325.1953** | **-** | **-** | **1,360,024 B** | +| LazyExecutionAndPublication | 10000 | 187,679.63 ns | 3,718.996 ns | 5,090.604 ns | 1.04 | 0.03 | 325.1953 | - | - | 1,360,024 B | +| SLazy | 10000 | 139,473.31 ns | 2,775.461 ns | 5,280.603 ns | 0.76 | 0.02 | 229.4922 | - | - | 960,024 B | +| ValueLazy | 10000 | 85,404.33 ns | 615.786 ns | 514.209 ns | 0.47 | 0.01 | 152.9541 | - | - | 640,024 B | diff --git a/Tools/docfx_project/benchmarks/SLazyInitializationBenchmarks.md b/Tools/docfx_project/benchmarks/SLazyInitializationBenchmarks.md index caff3e1c..f5bb6172 100644 --- a/Tools/docfx_project/benchmarks/SLazyInitializationBenchmarks.md +++ b/Tools/docfx_project/benchmarks/SLazyInitializationBenchmarks.md @@ -10,30 +10,35 @@ BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19042.1110 (20H2/October2020Update) Intel Core i7-4790K CPU 4.00GHz (Haswell), 1 CPU, 8 logical and 4 physical cores .NET SDK=6.0.100-preview.6.21355.2 [Host] : .NET 5.0.8 (5.0.821.31504), X64 RyuJIT - Job-BVARYK : .NET 5.0.8 (5.0.821.31504), X64 RyuJIT + Job-VQFEFS : .NET 5.0.8 (5.0.821.31504), X64 RyuJIT InvocationCount=1 UnrollFactor=1 ``` -| Method | N | Mean | Error | StdDev | Median | Ratio | RatioSD | -|---------------------------- |------ |-------------:|-------------:|-------------:|-------------:|------:|--------:| -| **Lazy** | **1** | **400.0 ns** | **0.00 ns** | **0.00 ns** | **400.0 ns** | **1.00** | **0.00** | -| LazyExecutionAndPublication | 1 | 400.0 ns | 0.00 ns | 0.00 ns | 400.0 ns | 1.00 | 0.00 | -| SLazy | 1 | 200.0 ns | 0.00 ns | 0.00 ns | 200.0 ns | 0.50 | 0.00 | -| | | | | | | | | -| **Lazy** | **10** | **670.9 ns** | **21.74 ns** | **59.14 ns** | **700.0 ns** | **1.00** | **0.00** | -| LazyExecutionAndPublication | 10 | 653.6 ns | 18.66 ns | 54.13 ns | 700.0 ns | 0.99 | 0.11 | -| SLazy | 10 | 456.6 ns | 20.18 ns | 59.18 ns | 500.0 ns | 0.69 | 0.10 | -| | | | | | | | | -| **Lazy** | **100** | **2,916.7 ns** | **57.79 ns** | **61.83 ns** | **2,900.0 ns** | **1.00** | **0.00** | -| LazyExecutionAndPublication | 100 | 2,915.0 ns | 58.25 ns | 67.08 ns | 2,900.0 ns | 1.00 | 0.03 | -| SLazy | 100 | 2,252.9 ns | 46.33 ns | 74.81 ns | 2,200.0 ns | 0.78 | 0.03 | -| | | | | | | | | -| **Lazy** | **1000** | **25,335.7 ns** | **475.74 ns** | **421.73 ns** | **25,150.0 ns** | **1.00** | **0.00** | -| LazyExecutionAndPublication | 1000 | 25,042.9 ns | 268.10 ns | 237.66 ns | 24,900.0 ns | 0.99 | 0.02 | -| SLazy | 1000 | 19,716.7 ns | 106.93 ns | 83.48 ns | 19,700.0 ns | 0.78 | 0.01 | -| | | | | | | | | -| **Lazy** | **10000** | **223,144.9 ns** | **11,838.31 ns** | **34,532.90 ns** | **212,750.0 ns** | **1.00** | **0.00** | -| LazyExecutionAndPublication | 10000 | 221,203.1 ns | 12,431.72 ns | 36,066.68 ns | 203,500.0 ns | 1.00 | 0.17 | -| SLazy | 10000 | 196,614.6 ns | 7,590.36 ns | 22,261.20 ns | 193,650.0 ns | 0.90 | 0.13 | +| Method | N | Mean | Error | StdDev | Median | Ratio | RatioSD | +|---------------------------- |------ |-------------:|------------:|-------------:|-------------:|------:|--------:| +| **Lazy** | **1** | **400.0 ns** | **0.00 ns** | **0.00 ns** | **400.0 ns** | **1.00** | **0.00** | +| LazyExecutionAndPublication | 1 | 400.0 ns | 0.00 ns | 0.00 ns | 400.0 ns | 1.00 | 0.00 | +| SLazy | 1 | 290.2 ns | 10.59 ns | 29.87 ns | 300.0 ns | 0.68 | 0.12 | +| ValueLazy | 1 | 300.0 ns | 0.00 ns | 0.00 ns | 300.0 ns | 0.75 | 0.00 | +| | | | | | | | | +| **Lazy** | **10** | **669.7 ns** | **19.15 ns** | **56.16 ns** | **700.0 ns** | **1.00** | **0.00** | +| LazyExecutionAndPublication | 10 | 660.6 ns | 19.38 ns | 55.30 ns | 700.0 ns | 0.99 | 0.11 | +| SLazy | 10 | 478.3 ns | 14.70 ns | 41.47 ns | 500.0 ns | 0.72 | 0.09 | +| ValueLazy | 10 | 474.2 ns | 15.15 ns | 43.97 ns | 500.0 ns | 0.71 | 0.08 | +| | | | | | | | | +| **Lazy** | **100** | **2,931.8 ns** | **58.32 ns** | **71.62 ns** | **2,900.0 ns** | **1.00** | **0.00** | +| LazyExecutionAndPublication | 100 | 2,873.3 ns | 48.93 ns | 45.77 ns | 2,900.0 ns | 0.98 | 0.03 | +| SLazy | 100 | 2,272.0 ns | 45.97 ns | 61.37 ns | 2,300.0 ns | 0.77 | 0.03 | +| ValueLazy | 100 | 2,314.3 ns | 40.16 ns | 47.81 ns | 2,300.0 ns | 0.79 | 0.03 | +| | | | | | | | | +| **Lazy** | **1000** | **24,971.4 ns** | **214.17 ns** | **189.85 ns** | **24,900.0 ns** | **1.00** | **0.00** | +| LazyExecutionAndPublication | 1000 | 24,908.3 ns | 247.03 ns | 192.87 ns | 24,900.0 ns | 1.00 | 0.01 | +| SLazy | 1000 | 19,850.0 ns | 66.89 ns | 52.22 ns | 19,850.0 ns | 0.79 | 0.01 | +| ValueLazy | 1000 | 20,313.3 ns | 387.29 ns | 362.27 ns | 20,100.0 ns | 0.81 | 0.02 | +| | | | | | | | | +| **Lazy** | **10000** | **199,220.0 ns** | **5,568.43 ns** | **15,522.57 ns** | **192,000.0 ns** | **1.00** | **0.00** | +| LazyExecutionAndPublication | 10000 | 202,664.4 ns | 7,030.86 ns | 19,599.23 ns | 193,250.0 ns | 1.02 | 0.13 | +| SLazy | 10000 | 182,331.1 ns | 4,032.21 ns | 11,240.20 ns | 178,550.0 ns | 0.92 | 0.09 | +| ValueLazy | 10000 | 182,376.6 ns | 5,121.04 ns | 14,610.60 ns | 175,350.0 ns | 0.92 | 0.09 |