[英]Should this C# code be refactored to use the Lazy<T> class instead?
I have the following code which could be called via multiple web-requests at the same second. 我有以下代码,可以在同一秒通过多个Web请求来调用。 As such, I don't want the second+ request hitting the database, but waiting until the first one does. 因此,我不希望第二个以上的请求到达数据库,而是等到第一个以上的请求到达数据库。
Should I refactor this to use the Lazy<T>
keyword
class instead? 我应该将其重构为使用Lazy<T>
关键字
类吗? If 10 calls to a Lazy<T>
piece of code occur at the same time, do 9 of those calls wait for the first one to complete? 如果同时发生10个对Lazy<T>
代码的调用,这些调用中有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
}
Yes you can use Lazy<T>
是的,您可以使用Lazy<T>
By default, Lazy objects are thread-safe. 默认情况下,惰性对象是线程安全的。 That is, if the constructor does not specify the kind of thread safety, the Lazy objects it creates are thread-safe. 也就是说,如果构造函数未指定线程安全的类型,则它创建的Lazy对象是线程安全的。 In multithreaded scenarios, the first thread to access the Value property of a thread-safe Lazy object initializes it for all subsequent accesses on all threads , and all threads share the same data. 在多线程方案中,第一个访问线程安全的Lazy对象的Value属性的线程将其初始化,以用于所有线程上的所有后续访问 ,并且所有线程共享相同的数据。 Therefore, it does not matter which thread initializes the object, and race conditions are benign. 因此,哪个线程初始化对象都没有关系,并且竞争条件是良性的。
And yes, it's not a keyword - its a .NET framework class that formalizes the often required use case for lazy initialization and offers this out of the box so you don't have to do it "manually". 是的,它不是关键字-它是一个.NET框架类,用于正规化懒惰初始化所需的用例,并提供了开箱即用的功能,因此您不必“手动”进行操作。
As @BrokenGlass pointed out it is safe. 正如@BrokenGlass指出的那样,它是安全的。 But I couldn't resist and had to make a test... 但是我无法抗拒,不得不做个测试...
Only one thread id is printed... 仅打印一个线程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();
}
But, which one is faster? 但是,哪个更快? From the results I got... 从结果我得到...
Executing the code 100 times 执行代码100次
[ Lazy: 00:00:01.003 ]
[ Field: 00:00:01.000 ]
Executing the code 100000000 times 执行代码100000000次
[ Lazy: 00:00:10.516 ]
[ Field: 00:00:17.969 ]
Test code: 测试代码:
Performance.Test("Lazy", TestAmount, false,
() =>
{
var laz = lazyInt.Value;
});
Performance.Test("Field", TestAmount, false,
() =>
{
var laz = FieldInt;
});
Test method: 测试方法:
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"));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.