在c#中,如何在多线程环境中迭代IEnumerable [英] In c# , how to iterate IEnumerable in multithreading environment

查看:66
本文介绍了在c#中,如何在多线程环境中迭代IEnumerable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这种情况下,有一个大型词典由一个线程以相当高的频率随机更新,而另一个线程试图获取该词典的快照以保存为历史记录. 我目前使用的是这样的东西:

I am in this situation that there is a large dictionary that is randomly updated by one thread at a fairly high frequency, and there is another thread that tries to take a snapshot of the dictionary to save as history. I currently using something like this:

Dictionary<string, object> dict = new Dictionary<string, object>();
var items = dict.Values.ToList();

这在大多数情况下都可以正常工作,只是偶尔会抛出:

This works fine for most of the time, except it occasionally throws:

System.InvalidOperationException:集合已修改;枚举 操作可能无法执行.

System.InvalidOperationException: Collection was modified; enumeration operation may not execute.

我理解为什么会这样,但是我不知道该怎么做才能避免集合修改错误.

I understand why this happen, but I don't know what can I do to avoid the collection modified error.

迭代此类集合的最佳方法是什么?

What is the best approach to iterate such collection?

我也尝试了ConcurrentDictionary,但是没有运气. 为什么? ConcurrentDictionary线程仅在项目级别安全吗?

I also tried ConcurrentDictionary, but no luck. Why? Is ConcurrentDictionary thread safe only at item level?

推荐答案

根据

According to the docs you should be able to use the GetEnumerator() method of ConcurrentDictionary to get a thread-safe iterator.

从字典返回的枚举数可以安全地与对字典的读取和写入同时使用,但是它不代表字典的即时快照.通过枚举器公开的内容可能包含在调用GetEnumerator之后对字典所做的修改.

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 GetEnumerator was called.

由于您正在处理并发线程,因此在一致性方面需要进行一些折衷也就不足为奇了,但是我希望这种方法比其他答案中给出的强力方法具有更少的阻塞性.如果您尝试过,那将行不通:

Since you're dealing with concurrent threads, it's not surprising to have some tradeoffs with consistency, but I would expect this approach to block less than the brute force approach given in other answers. This wouldn't have worked if you tried:

var items = concurrentDict.Items.ToList();

但它应该适用于

var items = concurrentDict.GetEnumerator();

或者您可以直接直接引用迭代器:

or you could simply reference the iterator directly:

foreach(var item in concurrentDict)
{
    valueList.Add(item.Value);
}

这篇关于在c#中,如何在多线程环境中迭代IEnumerable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆