Конференция "WinAPI" » Многопоточность. Запись логов
 
  • Игорь Шевченко © (31.10.17 10:35) [20]
    Eraser ©   (30.10.17 23:02) [19]


    > могут появится огромные просадки в процедуре логирования,
    >  сталкивался с таким


    Я не сталкивался. Если кто протоколирует большой объем в файлах на диске, весьма разумно будет задать ему вопрос: а нафига ?

    И потом мне крайне странно поведение антивируса, который а) не может быть настроен на исключения б) занимается анализом файла при каждой его модификации.

    Что-то тут не так.
  • Eraser © (31.10.17 14:55) [21]

    > Игорь Шевченко ©   (31.10.17 10:35) [20]


    > Если кто протоколирует большой объем в файлах на диске,
    > весьма разумно будет задать ему вопрос: а нафига ?

    Большой объем - понятие растяжимое. В моем случае это высоконагруженный сервер (около сотни тысяч одновременных соединений) на базе IOCP. Если в рабочем потоке использовать прямое логирование на диск, это дает серьезную деградацию производительности, если не подводит память, даже без антивируса. Собственно, это в любой статье по IOCP написано, что в рабочих потоках не должно быть блокирующих, на хоть сколько то заметное время вызовов, да и из здравого смысла это понятно. Даже если логировать исключительно только факт соединения. Представьте, когда одновременно нужно записать несколько десятков тысяч записей из 30 потоков, допустим, после перезапуска сервера.


    > И потом мне крайне странно поведение антивируса, который
    > а) не может быть настроен на исключения б) занимается анализом
    > файла при каждой его модификации.

    не правильно заставлять юзеров что-то там настраивать. хотя, в моем случае, ПО не для сторонних юзеров.

    скорее всего, с данной проблемой столкнутся единицы, но, тем не менее, она есть.
  • Игорь Шевченко © (31.10.17 18:30) [22]
    Eraser ©   (31.10.17 14:55) [21]

    Для начала, давай не будем сваливать все протоколы в одну кучу, они, как минимум, имеют разное назначение и, что весьма вероятно, в зависимости от назначения могут быть по-разному реализованы.

    Я в [18] говорил о некоем alert.log по образу и подобию Oracle, большое количество информации там может появится в случае какой-то отладочного вывода, но, тем не менее, все равно, тормозов я не наблюдал. Другие протоколы, штатные, пишутся отдельным процессом (а то и несколькими, в зависимости от нагрузки) в базу данных, в электронную почту и т.п., а не на диск. Но и там особо информации немного, потому что писать огромные логи лично я не вижу причины. Возможно, в каких-то задачах это и оправдано.
    И еще раз - реализация зависит от задачи, нет тут серебряной пули.
  • Eraser © (31.10.17 22:25) [23]

    > Игорь Шевченко ©   (31.10.17 18:30) [22]

    ну автор то не указал, что именно он логирует и в каком объеме.
    простое логирование в т.ч. крэш лог сделаны просто, примерно так, как тут уже показывали

    function InternalAppendLogToFile(const AMsg: string): Boolean;
    var
     fText: TextFile;
     sFileName: string;
    begin
     Result := False;

     try
       sFileName := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)));
       if not DirectoryExists(sFileName + 'Logs') then
         MkDir(sFileName + 'Logs');
       sFileName := sFileName + 'Logs\' + _sExeName + '_' + FormatDateTime('yyyy_mm', Now) +
         '_log.txt';
     except
       Exit;
     end;

     EnterCriticalSection(_csUniversalLog);
     try
       AssignFile(fText, sFileName);
       if FileExists(sFileName) then
         Append(fText)
       else
         Rewrite(fText);
       try
         Writeln(fText, AMsg);
       finally
         CloseFile(fText);
       end;

       Result := True;
     finally
       LeaveCriticalSection(_csUniversalLog);
     end;
    end;

    function AppendLog(const AMsg: string; AForceToFile: Boolean = False): Boolean;
    var
     sText: string;
    begin
     Result := False;

     sText := FormatDateTime('dd-mm-yyyy_hh:nn:ss:zzz', Now) + '#T:' + AMsg;
     OutputDebugString(PChar(sText));

     {$IFDEF USE_FILE}
     Result := InternalAppendLogToFile(sText);
     {$ENDIF}

     if (not Result) and AForceToFile then
       Result := InternalAppendLogToFile(sText);
    end;
  • han_malign © (01.11.17 10:50) [24]

    > Собственно, это в любой статье по IOCP написано, что в рабочих
    > потоках не должно быть блокирующих, на хоть сколько то заметное
    > время вызовов

    - в IOCP кстати есть неочевидный нюансик - зачем нужен параметр NumberOfConcurrentThreads, если можно просто не создавать лишних потоков:
    - если количество активных потоков ассоциированных с одним портом уже NumberOfConcurrentThreads, но один из потоков переходит в режим ожидания не по причине GetQueuedCompletionStatus - например на ожидании другой I/O операции, то разблокируется еще один поток(в результате чего в некоторые моменты времени количество активных потоков может быть больше NumberOfConcurrentThreads)...

    ...
    This is one reason to have your application create more threads in its thread pool than the concurrency value.
  • Alex Konshin © (03.12.17 21:27) [25]
    > Eraser ©   (31.10.17 14:55) [21]
    Согласен, что такое иногда нужно и что неверное решение очень сильно (иногда на порядки) снижает производительность.
    В таком случае логирование нужно делать в отдельном треде с входной очередью-буфером, которая либо синхронизирована, либо поддерживает асинхронное добавление без бликировки. Тред выбирает сообщения из очереди и пишет в выходной буфер. Буфер сбрасывается на диск при заполнении или после короткой задержки (чтоб не инициировалась запись слишком часто и мелкими порциями). Сама запись на диск может осуществляться либо ещё в одном отдельном треде или с помощью операций асинхроной записи.

    Уже не помню, делал ли я так где-нибудь на Delphi, но на Java я точно такое реализовывал в нескольких проектах.
  • Alex Konshin © (03.12.17 21:27) [25]
    > Eraser ©   (31.10.17 14:55) [21]
    Согласен, что такое иногда нужно и что неверное решение очень сильно (иногда на порядки) снижает производительность.
    В таком случае логирование нужно делать в отдельном треде с входной очередью-буфером, которая либо синхронизирована, либо поддерживает асинхронное добавление без бликировки. Тред выбирает сообщения из очереди и пишет в выходной буфер. Буфер сбрасывается на диск при заполнении или после короткой задержки (чтоб не инициировалась запись слишком часто и мелкими порциями). Сама запись на диск может осуществляться либо ещё в одном отдельном треде или с помощью операций асинхроной записи.

    Уже не помню, делал ли я так где-нибудь на Delphi, но на Java я точно такое реализовывал в нескольких проектах.
  • Дмитрий Белькевич © (03.12.17 23:04) [26]

    > И потом мне крайне странно поведение антивируса, который
    > а) не может быть настроен на исключения б) занимается анализом
    > файла при каждой его модификации.
    >


    Антивирусы вообще редкие каки. Каких уж чудес я с ними не видел.

    Немного в тему. У нас на одной из установок периодически установка атрибутов (FileSetAttr) вывешивает гуй, нашли с помощью эврики. Ладно бы еще запись в файл. Грешим, правда, скорее на виртуалку. Пришлось выносить в отдельный поток.
  • Дмитрий Белькевич © (03.12.17 23:04) [26]

    > И потом мне крайне странно поведение антивируса, который
    > а) не может быть настроен на исключения б) занимается анализом
    > файла при каждой его модификации.
    >


    Антивирусы вообще редкие каки. Каких уж чудес я с ними не видел.

    Немного в тему. У нас на одной из установок периодически установка атрибутов (FileSetAttr) вывешивает гуй, нашли с помощью эврики. Ладно бы еще запись в файл. Грешим, правда, скорее на виртуалку. Пришлось выносить в отдельный поток.
 
Конференция "WinAPI" » Многопоточность. Запись логов
Есть новые Нет новых   [118233   +45][b:0][p:0]