C# 为什么我会得到;“收藏已修改”;当I';我只是在读数值?
我有一个多线程控制台项目,它与RFID天线相连,当打开天线时,天线会不断扫描。我在他们面前有大约500个RFID标签,他们每30秒扫描15000到20000个 我最初打算使用ConcurrentDictionary或ConcurrentDictionary的惰性版本,但它没有添加(可能也没有更新)标记。我通过创建一个字符串的基本列表类并将标记存储在扫描标记的同一事件中来验证这一点,在一个单独的计时器事件中,我将基本列表的不同列表与两个ConcurrentDictionary进行了比较 为了解释ConcurrentDictionary的使用,我保存了一个struct对象,该对象包含一个datetime属性(时间扫描)和一个expired属性,以便在计时器事件中,我可以清除过期项目的集合。struct对象使用一个timespan对象来表示它在过期之前的有效期。我正在使用ConcurrentDictionary的两个版本,因为我仍在测试哪一个更好 然后我想保留字符串的通用列表,并将其用作原始数据收集器,每隔30秒左右,获取不同的值并循环它们,然后使用addorupdate更新ConcurrentDictionary。这里的问题是,我在迭代泛型列表时遇到了InvalidOperation异常(集合被修改),即使我只读取这些值。下面是循环。我还尝试复制泛型列表,并在循环中使用ToList(),但仍然得到了异常C# 为什么我会得到;“收藏已修改”;当I';我只是在读数值?,c#,collections,concurrency,C#,Collections,Concurrency,我有一个多线程控制台项目,它与RFID天线相连,当打开天线时,天线会不断扫描。我在他们面前有大约500个RFID标签,他们每30秒扫描15000到20000个 我最初打算使用ConcurrentDictionary或ConcurrentDictionary的惰性版本,但它没有添加(可能也没有更新)标记。我通过创建一个字符串的基本列表类并将标记存储在扫描标记的同一事件中来验证这一点,在一个单独的计时器事件中,我将基本列表的不同列表与两个ConcurrentDictionary进行了比较 为了解释C
static LazyConDeDupe<string, ConEntry> lDedupe = new LazyConDeDupe<string, ConEntry>(new TimeSpan(0, 0, 30));
static private ConDeDupe dc = new ConDeDupe(new TimeSpan(0, 0, 30));
static private List<string> epcs = new List<string>();
private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
List<string> missingList;
List<string> lazyMissingList;
lock (epcs)
{
List<string> disScans = epcs.Distinct().ToList();
for (int i = 0; i <= disScans.Count - 1; i++)
{
dc.Add(disScans[i], System.DateTime.UtcNow);
lDedupe.AddorUpdate(disScans[i], (k) => new ConEntry(System.DateTime.UtcNow, new TimeSpan(0, 0, 30)),
(r, v) => new ConEntry(DateTime.UtcNow, new TimeSpan(0, 0, 30)));
}
missingList = dc.FindNonExistantKeys(epcs);
lazyMissingList = lDedupe.FindNonExistantKeys(epcs);
if (missingList.Count > 0)
{
System.Diagnostics.Debug.WriteLine("Found EPCs Missing");
System.Diagnostics.Debug.WriteLine(string.Format(@"Raw Count: {0}, Missing: {1}", epcs.Count.ToString(), missingList.Count.ToString()));
missingList.ForEach(x => System.Diagnostics.Debug.WriteLine(String.Format("Missing EPC: {0}", x)));
System.Diagnostics.Debug.WriteLine(string.Format(@"Raw Count: {0}, Lazy Missing: {1}", epcs.Count.ToString(), lazyMissingList.Count.ToString()));
System.Diagnostics.Debug.WriteLine(string.Format(@"Distinct Raw Count: {0}", disScans.ToList().Distinct().Count().ToString()));
}
else
{
System.Diagnostics.Debug.WriteLine("None Missing - EPCs in List");
System.Diagnostics.Debug.WriteLine(string.Format(@"Raw Count: {0}, Missing: {1}", epcs.Count.ToString(), missingList.Count.ToString()));
System.Diagnostics.Debug.WriteLine(string.Format(@"Raw Count: {0}, Lazy Missing: {1}", epcs.Count.ToString(), lazyMissingList.Count.ToString()));
System.Diagnostics.Debug.WriteLine(string.Format(@"Distinct Raw Count: {0}", disScans.ToList().Distinct().Count().ToString()));
}
epcs.Clear();
}
if (dc.Count > 100000)
{
dc.CleanUp();
}
else if(lazyMissingList.Count > 0) lDedupe.CleanUp();
}
private static void OnTagsReported(ImpinjReader sender, TagReport report)
{
//MessageBox.Show(string.Format("RFID Scanned, Tags:{0}", report.Tags.Count.ToString()));
foreach (Tag tag in report)
{
Console.WriteLine(string.Format(@"EPC: {0}", tag.Epc.ToString()));
try
{
//dc.Add(tag.Epc.ToString(), System.DateTime.UtcNow);
//lDedupe.AddorUpdate(tag.Epc.ToString(), (k) => new ConEntry(System.DateTime.UtcNow, new TimeSpan(0, 0, 30)),
// (r, v) => new ConEntry(DateTime.UtcNow, new TimeSpan(0, 0, 30)));
epcs.Add(tag.Epc.ToString());
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
static lazycondepe ldedepe=新的lazycondepe(新的时间跨度(0,0,30));
静态私有ConDeDupe dc=新ConDeDupe(新时间跨度(0,0,30));
静态私有列表epcs=新列表();
私有静态无效计时器(对象发送器,System.Timers.ElapsedEventArgs e)
{
列表丢失列表;
列表lazyMissingList;
锁(epcs)
{
List disScans=epcs.Distinct().ToList();
对于(int i=0;i new ConEntry(System.DateTime.UtcNow,new TimeSpan(0,0,30)),
(r,v)=>newconentry(DateTime.UtcNow,newtimespan(0,0,30));
}
missingList=dc.FindNonExistantKeys(epcs);
lazyMissingList=ldedepe.FindNonExistantKeys(epcs);
如果(missingList.Count>0)
{
System.Diagnostics.Debug.WriteLine(“发现缺少EPC”);
System.Diagnostics.Debug.WriteLine(string.Format(@“原始计数:{0},缺少:{1}”、epcs.Count.ToString()、missingList.Count.ToString());
missingList.ForEach(x=>System.Diagnostics.Debug.WriteLine(String.Format(“Missing EPC:{0}”,x));
System.Diagnostics.Debug.WriteLine(string.Format(@“原始计数:{0},惰性缺失:{1}”、epcs.Count.ToString()、lazyMissingList.Count.ToString());
System.Diagnostics.Debug.WriteLine(string.Format(@“Distinct Raw Count:{0}”,disScans.ToList().Distinct().Count().ToString());
}
其他的
{
System.Diagnostics.Debug.WriteLine(“无缺失-列表中的EPCs”);
System.Diagnostics.Debug.WriteLine(string.Format(@“原始计数:{0},缺少:{1}”、epcs.Count.ToString()、missingList.Count.ToString());
System.Diagnostics.Debug.WriteLine(string.Format(@“原始计数:{0},惰性缺失:{1}”、epcs.Count.ToString()、lazyMissingList.Count.ToString());
System.Diagnostics.Debug.WriteLine(string.Format(@“Distinct Raw Count:{0}”,disScans.ToList().Distinct().Count().ToString());
}
epcs.Clear();
}
如果(dc.Count>100000)
{
dc.CleanUp();
}
如果(lazyMissingList.Count>0)lDedupe.CleanUp(),则为else;
}
私有静态void OnTagsReported(ImpinjReader-sender,TagReport报告)
{
//Show(string.Format(“RFID扫描,标签:{0}”,report.Tags.Count.ToString());
foreach(报告中的标记)
{
WriteLine(string.Format(@“EPC:{0}”,tag.EPC.ToString());
尝试
{
//Add(tag.Epc.ToString(),System.DateTime.UtcNow);
//lDedupe.AddorUpdate(tag.Epc.ToString(),(k)=>new ConEntry(System.DateTime.UtcNow,new TimeSpan(0,0,30)),
//(r,v)=>newconentry(DateTime.UtcNow,newtimespan(0,0,30));
Add(tag.Epc.ToString());
}
捕获(例外情况除外)
{
系统.诊断.调试.写入线(例如消息);
}
}
}
为什么ConcurrentDictionary在某些情况下不能使用AddorUpdate方法进行更新?我试图做的基本想法是存储(添加)不同的扫描,修改它们上次扫描的时间(更新),并将它们保留一段时间,直到它们过期(删除)
编辑:
因此,我已经在“已过事件”中重新安排了代码,但为了使事情变得简单,问题发生在这段代码中
List<string> disScans = null;
lock (epcs)
{
disScans = epcs.Distinct().ToList(); <------- Error occurs here
epcs.Clear();
}
List disScans=null;
锁(epcs)
{
disScans=epcs.Distinct().ToList();2件事:1)尽管您正在从epcs(您的通用列表)创建disScans,但您仍可能在方法调用中迭代该列表:“missingList=dc.FindNonExistantKeys(epcs)”和“ldedepe.FindNonExistantKeys(epcs)”“.2)由于epcs是一个静态列表,因此是一个共享资源,并且不是并发的,因此您必须在访问它的任何地方锁定它,包括在您的OnTagsReported方法中。我正在迭代,但我在循环中调用ToList扩展方法,这也不起作用吗?foreach(rawData.ToList()中的字符串epc)因为您正在将epcs锁定在计时器中,所以您可以随意使用它—您不必调用epcs.Distinct().ToList().Howeve