【问题标题】:C# thread safely "refreshing" contents of a concurrentdictionaryC# 线程安全地“刷新”并发字典的内容
【发布时间】:2016-05-27 21:04:05
【问题描述】:

我正在使用一种接收列表的方法来更新字典。此列表包含应该存储在字典中的更新值。例如:我的字典中存储了值 1,2,3,4。一个线程尝试使用列表 0、1、3、5 更新字典中的值。我在该线程中的“刷新”方法需要从字典中删除 2,4,并添加 0,5。

我将有多个线程尝试快速连续地执行此“刷新”,因此我想确保它们的操作不会重叠并弄乱字典。因此,我需要每个尝试更新字典以完成其操作的线程,然后再移动到下一个线程。我还需要确保字典按照线程尝试更新的顺序进行更新。

在我当前的代码中,一个线程创建一个新列表,然后调用 Refresh() 来更新 SubscriptionCache 中的字典。在创建新列表之前,我让每个线程休眠 3-8 毫秒,然后使用新列表刷新字典。

看看我的代码:

public static class SubscriptionCache
    {
        private static ConcurrentDictionary<int, Subscription> _firstPartySubscriptionIds = new ConcurrentDictionary<int, Subscription>();

        //This compares the contents of the dictionary and new list,
        then updates the dictionary accordingly.
        internal static void Refresh(IEnumerable<Subscription> firstPartySubscriptionIds)
        {
          lock(_firstPartySubscriptionIds)
          {
            try
            {
                Compare(firstPartySubscriptionIds, true).ForEach((s) =>
                {
                    var t = _firstPartySubscriptionIds.TryAdd(s.GetHashCode(), s); Print("Added" + s.SystemID + " Success: " + t + " With Key: " + s.GetHashCode());
                });

                Compare(firstPartySubscriptionIds, false).ForEach((s) =>
                {
                    var t = _firstPartySubscriptionIds.TryRemove(s.GetHashCode(), out s); Print("Removed" + s.SystemID + "Success: " + t + " With key: " + s.GetHashCode());
                });


               LastRefreshedOn = DateTime.Now;
            }
            catch { }
          }
        }

        private static List<Subscription> Compare(IEnumerable<Subscription> firstPartySubscriptionIds, bool reverse)
        {
            var masterList = _firstPartySubscriptionIds.Values.ToList();
            var newList = firstPartySubscriptionIds.ToList();
            var returnList = new List<Subscription>();

            if (reverse == false)   // Returns elements in the old list which are NOT in the new list
            {
                foreach (Subscription s in masterList)
                {
                    if (!newList.Contains(s))
                    {
                        returnList.Add(s);
                    }
                }
            }
            else    //Returns elements in the new list which are NOT in the old list
            {
                foreach (Subscription s in newList)
                {
                    if (!masterList.Contains(s))
                    {
                        returnList.Add(s);
                    }
                }
            }
            return returnList;
        }

【问题讨论】:

  • 您确定简单的锁定会给您带来性能问题吗?
  • 你需要检查你的代码。
  • @Evk 现在我正在考虑它,我不明白没有它我的程序将如何工作。我想不出另一种可以在概念上起作用的方式。
  • 好吧,如果这是一个问题,问题也是如此。看来您的代码在该潜在锁定内没有执行任何繁重的操作(例如,不调用外部服务\数据库) - 所以无论如何锁定都没有问题。
  • @Evk 在 Refresh() 中锁定整个代码块后,我仍然遇到问题。这应该确保一次只有一个线程可以添加到字典中,但我确实需要线程按照它们创建的顺序添加到字典中。

标签: c# multithreading concurrentdictionary


【解决方案1】:

ConcurrentDictionary 不只是神奇地使涉及多线程的所有事情都工作。它只是使结构的所有方法在逻辑上原子。如果您想将多个操作作为单个原子操作执行(您似乎想要这样做),则需要显式管理您的线程来执行此操作(即通过锁定)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多