Parallel.ForEach IndexOutOfRangeException
Parallel.ForEach IndexOutOfRangeException
我正在尝试使用 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
我认为该集合不是线程安全的,您为什么认为它是线程安全的?
此外,您在处理消息时的操作也很可能以某种意想不到的方式改变了集合。
当 1 个线程就可以完成工作时,您希望通过编写复杂的多线程代码来实现什么?
并行循环的每个实例都写入同一个 evlog。所以一个循环正在设置源,而另一个循环已经是 运行.
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)
老实说,我会说在你炸毁宇宙之前去掉并行循环。
我正在尝试使用 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
我认为该集合不是线程安全的,您为什么认为它是线程安全的?
此外,您在处理消息时的操作也很可能以某种意想不到的方式改变了集合。
当 1 个线程就可以完成工作时,您希望通过编写复杂的多线程代码来实现什么?
并行循环的每个实例都写入同一个 evlog。所以一个循环正在设置源,而另一个循环已经是 运行.
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)
老实说,我会说在你炸毁宇宙之前去掉并行循环。