【问题标题】:Asp.net Core DI: Using SemaphoreSlim for write AND read operations with SingletonAsp.net Core DI:使用 SemaphoreSlim 通过 Singleton 进行读写操作
【发布时间】:2019-07-27 13:09:53
【问题描述】:

我正在重新设计一个 ASP.NET CORE 2.2 应用程序,以避免将服务定位器模式与静态类结合使用。双坏!

重新工具涉及创建和注入 Singleton 对象作为一些全局数据的存储库。这里的想法是避免在请求中反复使用一些基本/全局数据对我的 SQL 服务器造成影响。但是,这些数据需要每小时更新一次(不仅仅是在应用程序启动时)。因此,为了管理这种情况,我使用 SemaphoreSlim 来处理对数据对象的一次访问。

这是我正在做的事情的配对草图:

namespace MyApp.Global
{

    public interface IMyGlobalDataService
    {
        Task<List<ImportantDataItem>> GetFilteredDataOfMyList(string prop1);
        Task LoadMyImportantDataListAsync();
    }

    public class MyGlobalDataService: IMyGlobalDataService
    {
        private MyDbContext _myDbContext;

        private readonly SemaphoreSlim myImportantDataLock = new SemaphoreSlim(1, 1);
        private List<ImportantDataItem> myImportantDataList { get; set; }
        public async Task<List<ImportantDataItem>> GetFilteredDataOfMyList(string prop1)
        {
            List<ImportantDataItem> list;
            myImportantDataLock.WaitAsync();
            try
            {
                list = myImportantDataList.Where(itm => itm.Prop1 == prop1).ToList();
            }
            finally
            {
                myImportantDataLock.Release();
            }
            return list;
        }

        public async Task LoadMyImportantDataListAsync()
        {
            // this method gets called when the Service is created and once every hour thereafter

            myImportantDataLock.WaitAsync();
            try
            {
                this.MyImportantDataList = await _myDbContext.ImportantDataItems.ToListAsync();
            }
            finally
            {
                myImportantDataLock.Release();
            }
            return;
        }


        public MyGlobalDataService(MyDbContext myDbContext) {
            _myDbContext = myDbContext;
        };
    }
}

所以实际上我使用 SemaphoreSlim 来限制一次一个线程的访问,用于读取和更新到 myImportantDataList。这对我来说真的是一个不确定的领域。这似乎是处理我在整个应用程序中注入全局数据单例的合适方法吗?或者我应该期待疯狂的线程锁定/阻塞?

【问题讨论】:

    标签: c# dependency-injection singleton semaphore asp.net-core-2.2


    【解决方案1】:

    Creyke 的回答对我来说一针见血:使用 ReaderWriterLockSlim。因此,我已将其标记为已接受的答案。但是我发布了我修改后的解决方案,以防它对任何人都有帮助。需要注意的是,我使用以下包为 ReaderWriterLockSlim 提供异步功能:https://www.nuget.org/packages/Nito.AsyncEx/

    using Nito.AsyncEx;
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace MyApp.Global
    {
    
        public interface IMyGlobalDataService
        {
            Task<List<ImportantDataItem>> GetFilteredDataOfMyList(string prop1);
            Task LoadMyImportantDataListAsync();
        }
    
        public class MyGlobalDataService : IMyGlobalDataService
        {
            private MyDbContext _myDbContext;
    
            private readonly AsyncReaderWriterLock myImportantDataLock = new AsyncReaderWriterLock();
            private List<ImportantDataItem> myImportantDataList { get; set; }
            public async Task<List<ImportantDataItem>> GetFilteredDataOfMyList(string prop1)
            {
                List<ImportantDataItem> list;
                using (await myImportantDataLock.ReaderLockAsync())
                {
                    list = myImportantDataList.Where(itm => itm.Prop1 == prop1).ToList();
                }
                return list;
            }
    
            public async Task LoadMyImportantDataListAsync()
            {
                // this method gets called when the Service is created and once every hour thereafter
    
                using (await myImportantDataLock.WriterLockAsync())
                {
                    this.MyImportantDataList = await _myDbContext.ImportantDataItems.ToListAsync();
                }
                
                return;
            }
    
    
            public MyGlobalDataService(MyDbContext myDbContext)
            {
                _myDbContext = myDbContext;
            };
        }
    }

    【讨论】:

      【解决方案2】:

      使用SemaphoreSlim 的问题在于可扩展性。

      由于这是在 Web 应用程序中,因此可以公平地假设您希望多个读者同时访问数据。但是,您(可以理解)将可以同时生成的信号量请求数限制为 1(以防止并发读取和写入请求)。这意味着您也将序列化所有读取。

      您需要使用ReaderWriterLockSlim 之类的东西来允许多个线程进行读取,但要确保独占访问写入。

      【讨论】:

      • 是的,您正在表达我的直觉对我的建议。非常感谢您的反馈!将检查您在 ReaderWriterLockSlim 上的链接
      猜你喜欢
      • 2018-10-26
      • 1970-01-01
      • 2020-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-01
      • 1970-01-01
      • 2021-07-07
      相关资源
      最近更新 更多