尝试删除ConcurrentDictionary中的某些项时,正确的方法是什么

时间:2015-03-18 14:18:59

标签: c# dictionary concurrency

这样做会更好:

    public void Test()
    {

        ConcurrentDictionary<int, string> dictionary = new ConcurrentDictionary<int, string>();

        dictionary.TryAdd(0, "A");
        dictionary.TryAdd(1, "B");
        dictionary.TryAdd(2, "A");
        dictionary.TryAdd(3, "D");

        foreach (var item in dictionary)
        {
            string foundItem;

            if (dictionary.TryGetValue(item.Key, out foundItem))
            {
                if (foundItem == "A")
                {
                    if (dictionary.TryRemove(item.Key, out foundItem))
                    {
                        // Success
                    }
                }
            }
        }

    }  

比这个?:

    public void Test2()
    {

        ConcurrentDictionary<int, string> dictionary = new ConcurrentDictionary<int, string>();

        dictionary.TryAdd(0, "A");
        dictionary.TryAdd(1, "B");
        dictionary.TryAdd(2, "A");
        dictionary.TryAdd(3, "D");

        foreach (var item in dictionary)
        {
            string foundItem;

            if (item.Value == "A")
            {
                if (dictionary.TryRemove(item.Key, out foundItem))
                {
                    // Success
                }
            }
        }

    }  

此方法将由多个线程访问。

我的困惑是,每当我想删除某个项目时,我会尝试先将其删除,然后将其删除。但首先,我使用了foreach循环,这意味着我已经获得了该项目。任何想法都将不胜感激。

2 个答案:

答案 0 :(得分:4)

我认为第一种方法没有任何好处。我只是使用LINQ来查找项目:

foreach (var entry in dictionary.Where(e => e.Value == "A"))
{
    string ignored;
    // Do you actually need to check the return value?
    dictionary.TryRemove(entry.Key, out ignored);
}

当然,如果另一个线程添加值为"A"的新条目或更新现有条目(可能使值"A",可能需要考虑,您需要考虑要发生的事情。当你正在迭代时,值不是 - "A"对你来说这个条目是否被删除了吗?它不能保证会发生什么。(迭代器不会拍摄快照,但不是保证完全返回最新数据。)

希望通过检查我之后调用的"A"变量来检查您删除的值是否为ignored。这真的取决于你的背景。当您有多个线程修改地图时,您需要认为任何事情都可能发生 - 在您的代码实际执行的操作中。

还有一个事实是你实际上不得不浏览整本字典......你在其他地方用钥匙查找吗?

答案 1 :(得分:0)

第二种方法听起来不错。如果你有多个线程试图删除该项,其中一些将在TryRemove中失败,但一个会成功,这应该是好的。