我有一个多线程控制台项目,该项目绑定到RFID天线,该天线在打开时会不断扫描。我前面有大约500个RFID标签,它们每30秒扫描大约15000至20000个标签。
最初,我打算使用ConcurrentDictionary或ConcurrentDictionary的Lazy版本,但它没有添加(可能更新)标签。我通过创建一个基本的字符串List类并将标签存储在扫描标签的同一事件中来验证了这一点,并且在一个单独的计时器事件中,我将基本列表的不同列表与两个ConcurrentDictionaries进行了比较。
要解释有关ConcurrentDictionary的用法,我要保存一个结构对象,该结构对象包含一个datetime属性(扫描时间)和一个过期属性,以便在计时器事件中可以清除过期项的集合。 struct对象使用一个时间跨度对象,该对象说明它在过期之前可以使用多长时间。我正在使用这两个版本的ConcurrentDictionary,因为我仍在测试以查看哪个版本更好。
然后我想保留字符串的通用列表,并将其用作原始数据收集器,每隔30秒左右,获取不同的值并遍历它们,并使用addorupdate来更新ConcurrentDictionary。这里的问题是,即使我只读取值,我也正在获取InvalidOperation异常(对Collection进行了修改),该迭代遍历了通用列表的列表。循环在下面。我还尝试制作通用列表的副本,并在循环中使用ToList(),但仍然出现异常。
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);
}
}
}
为什么在某些情况下ConcurrentDictionary无法使用AddorUpdate方法进行更新?我要尝试的基本思想是存储(添加)不同的扫描,修改上次扫描的时间(更新)并将它们保留一定的时间,直到它们过期(删除)。
编辑: 因此,我在经过的事件中重新排列了代码,但为了使事情变得简单,此段代码中出现了问题。
List<string> disScans = null;
lock (epcs)
{
disScans = epcs.Distinct().ToList(); <------- Error occurs here
epcs.Clear();
}