当在ConcurrentDictionary上进行迭代并且仅进行读取时,ConcurrentDiction已锁定
本文关键字:ConcurrentDiction 锁定 读取 ConcurrentDictionary 迭代 当在 | 更新日期: 2023-09-27 18:08:46
- 我在我的网络应用程序中创建了一个ConcurrentDictionary作为应用程序对象。并且在会话之间共享。(基本上用作存储库。(
- 有时,任何可用会话都会向字典中添加一个新项目
仅允许管理员查看
现在,我想允许管理员列出字典中的所有值,但管理员不会添加或删除项目,相反,我只会为管理员提供一种方法,通过迭代项目来读取集合来查看项目。
(伪(代码看起来像这样:
foreach (var e in EmployeeCache.Instance.AllEmployees)
{
Console.WriteLine(e.Key);
}
我的问题是:
如果我遍历这些项,在读取ConcurrentDictionary时,它会被锁定吗?换句话说,ConcurrentDictionary是否已锁定,以便在管理代码简单地迭代ConcurrentDiction时,其他会话将无法添加或删除?
如果未锁定,您能解释一下吗
如果你认为它没有被锁定,你能快速总结一下它是如何做到这一点的吗?例如,它是否为只读操作创建了ConcurrentDictionary的副本,然后允许运行读取迭代——理解不会看到对实际字典的并发更改?
我试图确定的内容
我正在努力理解提供ConcurrentDictionary查看器的影响,该查看器可以由管理员经常刷新。例如,如果他们经常刷新它,会不会影响网络应用程序的性能。因为会话正在等待对象解锁以便添加/删除项目?
ConcurrentDictionary.GetEnumerator
就是这样实现的:
/// <remarks>
/// The enumerator returned from the dictionary is safe to use concurrently with
/// reads and writes to the dictionary, however it does not represent a moment-in-time
/// snapshot of the dictionary. The contents exposed through the enumerator may contain
/// modifications made to the dictionary after <see cref="GetEnumerator"/> was called.
/// </remarks>
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
Node[] buckets = m_tables.m_buckets;
for (int i = 0; i < buckets.Length; i++)
{
// The Volatile.Read ensures that the load of the fields of 'current'
// doesn't move before the load from buckets[i].
Node current = Volatile.Read<Node>(ref buckets[i]);
while (current != null)
{
yield return new KeyValuePair<TKey, TValue>(current.m_key, current.m_value);
current = current.m_next;
}
}
}
正如您所看到的,迭代是无锁的,并且只生成一个不可变的结构(KeyValuePair
(,该结构在每次迭代时返回给调用者。这就是为什么它不能保证ConcurrentDictionary
的快照及时
这肯定不会对迭代时添加/更新新值产生性能影响,但它不能保证您的管理员看到字典的最新快照。
- 您可以通过http://sourceof.net
- 您还可以查看"并发集合内部":Simon Cooper的ConcurrentDictionary
- 所有新的并发集合都是无锁的吗
这就是文档所说的:
从字典返回的枚举器可以安全使用同时阅读和写入字典,不管它做什么不代表字典的即时快照。这个通过枚举器公开的内容可能包含所做的修改在调用GetEnumerator之后将其添加到字典。
http://msdn.microsoft.com/en-us/library/dd287131(v=vs.110(.aspx
因此,如果您想要"快照"行为,则必须制作Keys集合的副本并对副本进行迭代,否则将对可变线程安全集合进行迭代。