我尝试使用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();
这是我在de console中看到的:
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
答案 0 :(得分:3)
dictLogs被多个线程同时添加到了。如果这是一个普通的字典,这将给你带来问题。
问问自己
时会发生什么dictLogs.Add(ID, new List<string>());
在同一时间被调用。
您与
存在同样的问题Logs[logname]++;
其中相同的条目将由多个线程更新。但是,这不应该导致IndexOutOfRangeException,但会导致错误的计数。
您的ID已存在异常我认为是因为这个
ID = lognameWithoutSpaces + "_" + Logs[logname].ToString();
Logs [logname]可以同时具有相同的计数。因此,这将导致输入重复的密钥
另外
evlog.Source = logname;
可能不会导致任何异常,但它会给你不正确的结果,因为在它到达循环之前它可能会被另一个线程更改:
foreach (EventLogEntry message in evlog.Entries)
说实话,我会说在炸毁宇宙之前取出并行循环。
答案 1 :(得分:1)
我希望这个集合不是线程安全的,是什么让你觉得它是什么?
处理邮件时,您的操作很可能会以某种意外的方式更改集合。
当1个线程完成工作时,你想通过编写复杂的多线程代码来实现什么目标?
答案 2 :(得分:1)
并行循环的每个实例都写入相同的evlog。因此,一个循环是在另一个循环已经运行时设置Source。