У меня есть многопоточный консольный проект, который привязан к RFID-антеннам, которые при включении постоянно сканируют. У меня перед ними около 500 RFID-меток, и они сканируют от 15000 до 20000 за 30 секунд.
Сначала я собирался использовать ConcurrentDictionary или Lazy-версию ConcurrentDictionary, но он не добавлял (и, возможно, не обновлял) теги. Я проверил это, просто создав базовый класс строки List и сохранив тег в том же событии, в котором сканируется тег, и в отдельном событии таймера. Я сравнил отдельный список основного списка с обоими ConcurrentDictionaries.
Чтобы объяснить использование ConcurrentDictionary, я сохраняю объект struct, который содержит свойство datetime (время сканирования) и свойство expired, чтобы в моем событии timer я мог очистить коллекцию элементов с истекшим сроком. Объект struct принимает объект timepan, отмечающий, как долго он хорош до истечения срока его действия. Я использую обе версии ConcurrentDictionary, потому что я все еще проверяю, какая из них лучше.
Затем я подумал сохранить общий список строк и использовать его в качестве сборщика необработанных данных, и каждые 30 секунд или около того, получать отдельные значения и проходить через них и использовать addorupdate для обновления ConcurrentDictionary. Проблема в том, что я получаю исключения InvalidOperation (коллекция была изменена), повторяющий список общего списка, хотя я только читаю значения. Цикл ниже. Я также попытался сделать копию общего списка и использовать 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 в некоторых случаях? Основная идея, которую я пытаюсь сделать, это сохранить (добавить) отдельные сканы, изменить, когда они были в последний раз отсканированы (обновить), и удерживать их в течение определенного периода времени, пока они не истекут (удалить).
EDIT:
Таким образом, я перестроил свой код в прошедшем событии, но чтобы упростить задачу, проблема возникает в этом фрагменте кода.
List<string> disScans = null;
lock (epcs)
{
disScans = epcs.Distinct().ToList(); <------- Error occurs here
epcs.Clear();
}