Pur*_*ome 8 .net c# lazy-loading double-checked-locking
我有以下代码,可以在同一秒通过多个Web请求调用.因此,我不希望第二个+请求命中数据库,但等到第一个请求命中.
我应该重构这个来使用Lazy<T> 关键字 class吗?如果对Lazy<T>一段代码同时发生10次调用,那么这些调用中有9次会等待第一次调用完成吗?
public class ThemeService : IThemeService
{
private static readonly object SyncLock = new object();
private static IList<Theme> _themes;
private readonly IRepository<Theme> _themeRepository;
<snip snip snip>
#region Implementation of IThemeService
public IList<Theme> Find()
{
if (_themes == null)
{
lock (SyncLock)
{
if (_themes == null)
{
// Load all the themes from the Db.
_themes = _themeRepository.Find().ToList();
}
}
}
return _themes;
}
<sip snip snip>
#endregion
}
Run Code Online (Sandbox Code Playgroud)
正如@BrokenGlass指出它是安全的.但我无法抗拒,不得不进行测试......
只打印一个线程ID ...
private static Lazy<int> lazyInt;
// make it slow
private int fib()
{
Thread.Sleep(1000);
return 0;
}
public void Test()
{
// when run prints the thread id
lazyInt = new Lazy<int>(
() =>
{
Debug.WriteLine("ID: {0} ", Thread.CurrentThread.ManagedThreadId);
return fib();
});
var t1 = new Thread(() => { var x = lazyInt.Value; });
var t2 = new Thread(() => { var x = lazyInt.Value; });
var t3 = new Thread(() => { var x = lazyInt.Value; });
t1.Start();
t2.Start();
t3.Start();
t1.Join();
t2.Join();
t3.Join();
}
Run Code Online (Sandbox Code Playgroud)
但是,哪一个更快?从结果我得到...
执行代码100次
[ Lazy: 00:00:01.003 ]
[ Field: 00:00:01.000 ]
Run Code Online (Sandbox Code Playgroud)
执行代码100000000次
[ Lazy: 00:00:10.516 ]
[ Field: 00:00:17.969 ]
Run Code Online (Sandbox Code Playgroud)
测试代码:
Performance.Test("Lazy", TestAmount, false,
() =>
{
var laz = lazyInt.Value;
});
Performance.Test("Field", TestAmount, false,
() =>
{
var laz = FieldInt;
});
Run Code Online (Sandbox Code Playgroud)
测试方法:
public static void Test(string name, decimal times, bool precompile, Action fn)
{
if (precompile)
{
fn();
}
GC.Collect();
Thread.Sleep(2000);
var sw = new Stopwatch();
sw.Start();
for (decimal i = 0; i < times; ++i)
{
fn();
}
sw.Stop();
Console.WriteLine("[{0,15}: {1,-15}]", name, new DateTime(sw.Elapsed.Ticks).ToString("HH:mm:ss.fff"));
}
Run Code Online (Sandbox Code Playgroud)