提高并发字典访问 C# 的效率

本文关键字:访问 效率 字典 高并发 并发 | 更新日期: 2023-09-27 18:31:58

我有一个列表,多个后台线程可以访问该列表进行更新/读取。更新操作包括插入和删除。

为了同时执行此操作而不会出现同步问题,我在类中的私有只读对象上使用锁。

为了最大限度地减少在读取其数据时需要锁定列表的时间,我对它进行了深度克隆并返回深层克隆并解锁字典以进行插入/删除更新。

因此,每次读取列表都会增加我的服务的内存消耗。

需要注意的一点是,插入/删除是包含列表的类的内部。但阅读是供公众消费的。

我的问题是:

有什么方法可以避免克隆列表,并且仍然使用读/写锁同时使用它进行读取?

public class ServiceCache
    {
        private static List<Users> activeUsers;
        private static readonly object lockObject = new object();
        private static ServiceCache instance = new ServiceCache();
        public static ServiceCache Instance
        {
            get
            {
                return instance;
            }
        }
        private void AddUser(User newUser)
        {
            lock (lockObject)
            {
                //... add user logic
            }
        }
        private void RemoveUser(User currentUser)
        {
            lock (lockObject)
            {
                //... remove user logic
            }
        }
        public List<Users> ActiveUsers
        {
            get
            {
                lock (lockObject)
                {
                    //The cache returns deep copies of the users it holds, not links to the actual data.
                    return activeUsers.Select(au => au.DeepCopy()).ToList();
                }
            }
        }
    }

提高并发字典访问 C# 的效率

听起来

您需要使用 ConcurrentDictionary 类,并为要存储的每个Users对象创建一个键。然后,添加/更新用户变得如此简单:

_dictionary.AddOrUpdate("key", (k, v) =>
    {
        return newUser;
    }, (k, v) =>
    {
        return newUser;
    });

然后要删除,您将执行以下操作:

 Users value = null;
_dictionary.TryRemove("key", out value);

获取人员列表也非常容易,因为您只需要执行以下操作:

return _dictionary.Values.Select(x => x.Value).ToList();

它应该在那一刻返回字典内容的副本。

让 .NET 运行时为您处理线程。

您可以使用读写器锁来允许同时读取。

但是,使用ConcurrentDictionary和线程安全的不可变值,然后摆脱所有同步会快得多。

因此,每次读取列表都会增加内存消耗 我的服务。

为什么?调用方是否未释放引用?他们需要这样做,因为字典的内容可能会改变。

我认为您对复制所做的非常接近并发数据结构的工作方式,例如写入时复制集合,只是调用者无法保留引用。

其他几种方法:

  • 将同一副本返回给所有调用方,直到集合被修改。返回的集合应该是不可变的

  • 公开调用方希望从副本中获得的所有功能,并使用单个锁来处理原始列表