Насколько Thread-Safe - это NLog?

Что ж,

Я ждал несколько дней, прежде чем решить опубликовать этот вопрос, так как я не был уверен, как это изложить, перейдя к длинному подробному после. Однако я думаю, что здесь уместно обратиться за помощью к сообществу.

В основном, я пытался использовать 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 является потокобезопасным, но я ' Я прочитал несколько сообщений, в которых говорится о том, что это зависит от сценария использования. А как насчет моего дела? Мне нужно создать тысячи регистраторов (не все одновременно, но все же с очень высокой скоростью).

Обходной путь, который я нашел, - создать все регистраторы в ОДНОЙ ГЛАВНОЙ НИТИ; это ДЕЙСТВИТЕЛЬНО неудобно, поскольку я создаю все свои регистраторы приложений в начале приложения (своего рода пул регистраторов). И хотя это прекрасно работает, это просто НЕ приемлемый дизайн.

Итак, вы все это знаете, Ребята. Пожалуйста, помогите кодеру снова увидеть свою семью.

27
задан Mehdi LAMRANI 19 March 2012 в 10:50
поделиться