【发布时间】:2011-08-08 01:06:55
【问题描述】:
嗯,
我已经等了好几天才决定发布这个问题,因为我不知道如何陈述这一点,最终还是写了一篇很长的详细帖子。但是,我认为此时向社区寻求帮助是相关的。
基本上,我尝试使用 NLog 为数百个线程配置记录器。我认为这会非常简单,但是几十秒后我得到了这个异常: "InvalidOperationException : 集合被修改;枚举操作可能无法执行"
这里是代码。
//Launches threads that initiate loggers
class ThreadManager
{
//(...)
for (int i = 0; i<500; i++)
{
myWorker wk = new myWorker();
wk.RunWorkerAsync();
}
internal class myWorker : : BackgroundWorker
{
protected override void OnDoWork(DoWorkEventArgs e)
{
// "Logging" is Not static - Just to eliminate this possibility
// as an error culprit
Logging L = new Logging();
//myRandomID is a random 12 characters sequence
//iLog Method is detailed below
Logger log = L.iLog(myRandomID);
base.OnDoWork(e);
}
}
}
public class Logging
{
//ALL THis METHOD IS VERY BASIC NLOG SETTING - JUST FOR THE RECORD
public Logger iLog(string loggerID)
{
LoggingConfiguration config;
Logger logger;
FileTarget FileTarget;
LoggingRule Rule;
FileTarget = new FileTarget();
FileTarget.DeleteOldFileOnStartup = false;
FileTarget.FileName = "X:\\" + loggerID + ".log";
AsyncTargetWrapper asyncWrapper = new AsyncTargetWrapper();
asyncWrapper.QueueLimit = 5000;
asyncWrapper.OverflowAction = AsyncTargetWrapperOverflowAction.Discard;
asyncWrapper.WrappedTarget = FileTarget;
//config = new LoggingConfiguration(); //Tried to Fool NLog by this trick - bad idea as the LogManager need to keep track of all config content (which seems to cause my problem;
config = LogManager.Configuration;
config.AddTarget("File", asyncWrapper);
Rule = new LoggingRule(loggerID, LogLevel.Info, FileTarget);
lock (LogManager.Configuration.LoggingRules)
config.LoggingRules.Add(Rule);
LogManager.Configuration = config;
logger = LogManager.GetLogger(loggerID);
return logger;
}
}
所以我完成了我的工作,而不仅仅是在这里发布我的问题并享受家庭时光,我花了整个周末的时间来研究这个(幸运男孩!) 我下载了 NLOG 2.0 的最新稳定版本并将其包含在我的项目中。我能够追踪到它爆炸的确切位置:
在 LogFactory.cs 中:
internal void GetTargetsByLevelForLogger(string name, IList<LoggingRule> rules, TargetWithFilterChain[] targetsByLevel, TargetWithFilterChain[] lastTargetsByLevel)
{
//lock (rules)//<--Adding this does not fix it
foreach (LoggingRule rule in rules)//<-- BLOWS HERE
{
}
}
在 LoggingConfiguration.cs 中:
internal void FlushAllTargets(AsyncContinuation asyncContinuation)
{
var uniqueTargets = new List<Target>();
//lock (LoggingRules)//<--Adding this does not fix it
foreach (var rule in this.LoggingRules)//<-- BLOWS HERE
{
}
}
我的问题
因此,根据我的理解,发生的情况是 LogManager 混淆了,因为 从不同的线程调用 config.LoggingRules.Add(Rule) 而 GetTargetsByLevelForLogger 和 FlushAllTargets 正在被调用。
我试图搞砸 foreach 并用 for 循环替换它,但记录器变成了流氓(跳过了许多日志文件的创建)
太棒了终于
到处都写着 NLOG 是线程安全的,但我通过一些帖子进一步挖掘并声称这取决于使用场景。我的情况呢?
我必须创建数以千计的记录器(不是同时创建,但速度仍然非常快)。
我发现的解决方法是在同一主线程中创建所有记录器;这真的不方便,因为我在应用程序开始时创建了所有应用程序记录器(有点像记录器池)。 虽然效果很好,但它只是不可接受的设计。
所以大家都知道。 请帮助程序员再次见到他的家人。
【问题讨论】:
-
只是想知道,为什么你完全跳过反应灵敏的作者 (Jarek Kowalski):nlog-project.org/forum 请注意 2.0 仍被视为 Beta,最新的夜间构建甚至 alpha...
标签: c# multithreading logging nlog