是否应该重构此 C# 代码以使用 Lazy?类代替?

发布于 2024-12-01 05:44:01 字数 938 浏览 5 评论 0原文

我有以下代码,可以在同一秒通过多个网络请求调用。因此,我不希望第二个以上请求访问数据库,而是等到第一个请求访问数据库。

我应该重构它以使用 Lazy keyword 类吗?如果同时发生 10 次对 Lazy 代码段的调用,那么其中 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
}

I have the following code which could be called via multiple web-requests at the same second. 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? 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?

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
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南城旧梦 2024-12-08 05:44:01

Lazy

是的,您可以使用MSDN 一个>:

默认情况下,惰性对象是线程安全的。也就是说,如果
构造函数没有指定线程安全的种类,Lazy
它创建的对象是线程安全的。在多线程场景下,
第一个线程访问线程安全 Lazy 的 Value 属性
对象为所有线程上的所有后续访问初始化它,并且
所有线程共享相同的数据。因此,哪个并不重要
线程初始化对象,竞争条件是良性的。


是的,它不是一个关键字 - 它是一个 .NET 框架类,它形式化了延迟初始化经常需要的用例,并提供开箱即用的功能,因此您不必“手动”执行此操作。

Yes you can use Lazy<T>

From MSDN:

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. 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. 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".

¢蛋碎的人ぎ生 2024-12-08 05:44:01

正如@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();
}

但是,哪个更快?从我得到的结果来看...

执行代码 100 次

[   Lazy: 00:00:01.003   ]
[  Field: 00:00:01.000   ]

执行代码 100000000 次

[   Lazy: 00:00:10.516   ]
[  Field: 00:00:17.969   ]

测试代码:

Performance.Test("Lazy", TestAmount, false,
    () =>
    {
        var laz = lazyInt.Value;
    });

Performance.Test("Field", TestAmount, false,
    () =>
    {
        var laz = FieldInt;
    });

测试方法:

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"));
}

As @BrokenGlass pointed out it is safe. But I couldn't resist and had to make a test...

Only one thread id is printed...

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

[   Lazy: 00:00:01.003   ]
[  Field: 00:00:01.000   ]

Executing the code 100000000 times

[   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"));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文