使用yield和并发收集

时间:2015-03-17 13:33:18

标签: c# multithreading yield-return concurrentdictionary

这是另一个我讨论过的问题,但是我很好奇在使用并发字典和yield函数时会出现以下情况。

IEnumerable<int> GetValuesNotZero()
{
    foreach(int value in dictionary.Values)
    {
        if(value != 0)
        {
            yield return value;
        }
    }
}

如果另一个线程从字典中添加/删除/更新,那么foreach循环中的值会发生什么?在我迭代时字典是否被锁定,或者我是否还有丢失添加/删除/更新值的风险?

1 个答案:

答案 0 :(得分:2)

在您进行迭代时,如果另一个线程修改了字典,您将找到更新的值而不是异常(使用正常Dictionary<,>)。

如果您还没有达到修改过的项目,那么您最终会完成它;否则,如果您已访问过更新的元素,则可能会错过更新的值。

来自ConcurrentDictionary.GetEnumerator

  

从字典返回的枚举器可以安全使用   同时读取和写入字典,但它确实如此   不代表字典的即时快照。该   通过枚举器公开的内容可能包含所做的修改   在调用GetEnumerator之后到字典。

例如,假设Thread1正在遍历字典,现在位于第3位。如果在第7位修改了元素,则您将找到修改后的值。另一方面,如果它修改了位置1的元素,你就不会注意到它。 (忘记字典是无序的;使用位置来更好地理解)。


我刚刚意识到您的代码循环遍历Dictionary.Values(感谢@Svick在评论中提及);只有循环通过字典,上面的答案才会成立。当您在Values属性中进行迭代时,您实际上正在遍历快照。如果字典在同一时间更新,您将不会注意到它。