哪种方式是线程安全的并且具有更好的使用性能,ContainsKey或字符串索引器?

时间:2017-10-23 19:25:49

标签: c# .net hashtable

我有一个如下集合

private static readonly Dictionary<string,object> _AppCache = new Dictionary<string,object>;

然后我想知道哪一个更好用于检查是否存在密钥(我的密钥都没有空值)

  1. _AppCache.ContainsKey("x")
  2. _AppCache["x"] != null
  3. 此代码可能通过各种线程访问

    整个代码是:

    public void SetGlobalObject(string key, object value)
    {
        globalCacheLock.EnterWriteLock();
        try
        {
            if (!_AppCache.ContainsKey(key))
            {
                _AppCache.Add(key, value);
            }
        }
        finally
        {
            globalCacheLock.ExitWriteLock();
        }
    }
    

    更新

    我将代码更改为使用字典将问题的重点放在Conatinskey or Indexer

4 个答案:

答案 0 :(得分:3)

我不同意其他人使用Dictionary的建议。但是,为了回答您的问题,我认为您应该使用ContainsKey检查密钥是否存在有多种原因

  • 具体是ContainsKey写的是
  • 要使_AppCache["x"] != null正常工作,您的应用必须在未强制的假设下运行(没有值将为空)。这个假设现在可能适用,但未来的维护者可能不知道或理解这个关键假设,导致不直观的错误
  • ContainsKey的处理略少,尽管这不是很重要

这两个选项都不是线程安全的,所以这不是决定因素。为此,您需要使用锁定,或使用ConcurrentDictionary

如果您转到Dictionary(根据您的问题更新),答案更有利于ContainsKey。如果使用了index选项,则必须捕获异常以检测该键是否不在Dictionary中。 ContainsKey在您的代码中会更直接。

当密钥位于Dictionary时,ContainsKey的效率会略高一些。这两个选项首先调用内部方法FindEntry。在ContainsKey的情况下,它只返回结果。对于index选项,它还必须检索该值。如果密钥不在字典中,则索引选项的效率会相当低,因为它会抛出异常。

答案 1 :(得分:1)

您显然正在检查该密钥的存在。在这种情况下,如果密钥不存在,_AppCache["x"] != null将为您提供KeyNotFoundException,这可能并不理想。如果您确实想要检查密钥是否存在,而不通过检查生成异常,则必须使用_AppCache.ContainsKey("x")。为了检查密钥是否存在于字典或散列表中,我会坚持使用ContainsKey。如果!= null更快,那么性能上的任何差异都会被额外的代码所抵消,如果密钥确实不存在则会处理异常。

实际上,_AppCache["x"] != null不检查密钥是否存在,它正在检查,给定密钥&#34; x&#34;存在,关联的值是否为空。

无论哪种方式(尽管完成不同的任务)都能为您提供线程安全方面的任何优势。

所有这一切都适用于ConcurrentDictionary - 线程安全没有区别,这两种方式可以完成不同的事情,使用!=null进行检查时可能获得的任何增益都会被处理异常的其他代码所抵消。因此,请使用ContainsKey

答案 2 :(得分:1)

如果你担心线程安全,你应该看看ConcurrentDictionary类。

如果您不想使用ConcurrentDictionary,则必须确保同步对常规Dictionary<K,V>实例的访问。这意味着,通过锁定每次写入和读取操作,确保没有2个线程可以多次访问您的字典。

例如,如果您想以线程安全的方式向常规Dictionary添加内容,则必须这样做:

private readonly object _sync = new object();

// ...


lock( _sync )
{
    if( _dictionary.ContainsKey(someKey) == false )
    {
         _dictionary.Add(someKey, somevalue);
    }
}

自从引入通用Dictionary<K,V>类以来,你不应该继续使用Hashtable,因此在.NET 2.0中引入了类型安全的替代方案

使用Dictionary<K,V>时有一点需要注意:当您想要检索与给定键关联的值时,如果没有该指定键的条目,Dictionary将抛出异常,而Hashtable将返回null在那种情况下。

答案 3 :(得分:1)

您应该使用ConcurrentDictionary而不是字典,这本身就是线程安全的。因此,您不需要锁定(通常*)可以提高性能,因为锁定机制相当昂贵。

现在,仅检查条目是否存在我建议使用ContainsKey,而不管您使用哪个(并发)词典:

_AppCache.ContainsKey(key)

但是你可以使用GetOrAdd使用“并发字典”一步完成两个步骤:

_AppCache.GetOrAdd(key, value);

您既不需要锁也不会采取行动:

public void SetGlobalObject(string key, object value)
{
    _AppCache.GetOrAdd(key, value);
}

这不仅(可能*)表现更好,但我认为它表达了你的意图更清晰,更少杂乱。

(*)使用&#34;可能&#34;和&#34;一般&#34;这里要强调的是,这些数据结构确实具有大量的性能优化,但必须始终测量您的特定情况的性能。