Parallel.ForEach IndexOutOfRangeException
本文关键字:IndexOutOfRangeException ForEach Parallel | 更新日期: 2024-10-21 08:50:13
我正试图用Parallel.ForEach遍历我的事件日志。但它随机停止,ForEach上出现错误IndexOutOfRangeException。
这个:
foreach (EventLogEntry message in evlog.Entries)
有时它在第一次通过环路时停止,有时在已经通过环路44次之后停止。
此外,我有时会得到一个错误,即给定的ID已经存在。
这是我的完整代码:
string ID = null;
Logs.Add("System", 0);
Logs.Add("Application", 1000);
Logs.Add("Setup", 2000);
Logs.Add("Forwarded Events", 3000);
EventLog evlog = new EventLog();
evlog.MachineName = ".";
Parallel.ForEach(Logs.Keys, logname =>
{
System.Threading.Thread.Sleep(1000);
evlog.Source = logname;
string lognameWithoutSpaces = logname.Replace(" ", "");
foreach (EventLogEntry message in evlog.Entries)
{
string type = message.EntryType.ToString();
if (type == "0" | type == "Warning")
{
ID = lognameWithoutSpaces + "_" + Logs[logname].ToString();
Console.WriteLine("ID: " + ID);
dictLogs.Add(ID, new List<string>());
dictLogs[ID].Add(evlog.Log);
dictLogs[ID].Add(message.Source);
dictLogs[ID].Add(message.InstanceId.ToString());
dictLogs[ID].Add(type);
dictLogs[ID].Add(message.UserName);
dictLogs[ID].Add(message.TimeGenerated.ToString());
dictLogs[ID].Add(message.Category);
dictLogs[ID].Add(message.MachineName);
dictLogs[ID].Add(message.Message);
Logs[logname]++;
}
}
});
dictLogs.Clear();
这就是我在控制台上看到的:
ID: ForwardedEvents_3000
ID: System_0
ID: Setup_2000
ID: Application_1000
'DashboardBackEnd.vshost.exe' (CLR v4.0.30319: DashboardBackEnd.vshost.exe): Loaded 'C:'Windows'Microsoft.Net'assembly'GAC_MSIL'System.resources'v4.0_4.0.0.0_nl_b77a5c561934e089'System.resources.dll'. Module was built without symbols.
A first chance exception of type 'System.Collections.Generic.KeyNotFoundException' occurred in mscorlib.dll
A first chance exception of type 'System.IndexOutOfRangeException' occurred in System.dll
dictLogs由多个线程同时添加到。如果这是一本普通的字典,这会给你带来问题。
问问自己会发生什么
dictLogs.Add(ID, new List<string>());
在完全相同的时间调用。
也有同样的问题
Logs[logname]++;
其中相同的条目将由多个线程更新。但是,这不应导致IndexOutOfRangeException,而是会导致不正确的计数。
你的身份证已经存在,我想是因为这个
ID = lognameWithoutSpaces + "_" + Logs[logname].ToString();
日志[logname]可能同时具有相同的计数。因此,这将导致输入重复的密钥
还有
evlog.Source = logname;
可能不会引起任何异常,但它会给你不正确的结果,因为它可能在到达循环之前被另一个线程更改:
foreach (EventLogEntry message in evlog.Entries)
老实说,在你炸毁宇宙之前,我会说去掉平行循环
我认为这个集合不是线程安全的,你凭什么认为它是线程安全的?
此外,您在处理消息时的操作很可能会以某种意想不到的方式更改集合。
当一个线程可以完成这项工作时,您试图通过编写复杂的多线程代码来实现什么?
并行循环的每个实例都在写入同一个evlog。因此,一个循环正在设置Source,而另一个循环已经在运行。