Что ж,
Я ждал несколько дней, прежде чем решить опубликовать этот вопрос, так как я не был уверен, как это изложить, перейдя к длинному подробному после. Однако я думаю, что здесь уместно обратиться за помощью к сообществу.
В основном, я пытался использовать 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;
}
}
Итак, я выполнил свою работу, а не просто разместил здесь свой вопрос и имел семейное качество- время, выходные я потратил на это (Lucky Boy!) Я загрузил последнюю стабильную версию 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, но регистратор оказался некорректным (пропустив создание многих файлов журнала)
SOoooo НАКОНЕЦ
Везде написано, что NLOG является потокобезопасным, но я ' Я прочитал несколько сообщений, в которых говорится о том, что это зависит от сценария использования. А как насчет моего дела?
Мне нужно создать тысячи регистраторов (не все одновременно, но все же с очень высокой скоростью).
Обходной путь, который я нашел, - создать все регистраторы в ОДНОЙ ГЛАВНОЙ НИТИ; это ДЕЙСТВИТЕЛЬНО неудобно, поскольку я создаю все свои регистраторы приложений в начале приложения (своего рода пул регистраторов). И хотя это прекрасно работает, это просто НЕ приемлемый дизайн.
Итак, вы все это знаете, Ребята. Пожалуйста, помогите кодеру снова увидеть свою семью.