Python - Ведение журнала с использованием .format создает дополнительные циклы ЦП - PullRequest
0 голосов
/ 28 декабря 2018

test.py

import logging

# V1
logging.debug('%s before you %s', 'Look', 'leap!')

# V2
logging.debug('{} before you {}'.format('Look', 'leap!'))

У меня есть следующий код выше.

Верно ли это, когда я выполняю с python test.py --log=INFO V2 подвергнется дополнительному циклу ЦП, потому что он сначала отформатируетстрока и затем ничего не выводить из-за уровня отладки.

Есть ли в любом случае использовать .format стилизацию с ведением журнала и не использовать этот дополнительный цикл ЦП, если журнал в конечном итоге не выводится?

РЕДАКТИРОВАТЬ: Часть 1 -> Да, это правда с помощью этого кода тестирования (хотя и очень маленький)

old-format.py

import logging

# V1
for x in range(0, 100000):
    logging.debug('%s before you %s', 'Look', 'leap!')

new-format.py

import logging

# V2
for x in range(0, 100000):
    logging.debug('{} before you {}'.format('Look', 'leap!'))

python -m cProfile ~/Desktop/old-format.py -> 500464 функциональных вызова за 0,176 секунды

python -m cProfile ~/Desktop/new-format.py -> 600464 функциональных вызова за 0,237 секунды

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Серьезно, вы беспокоитесь о неправильной проблеме.Да, строка будет отформатирована и, возможно, в конечном итоге будет удалена.Нет, это не важно.

Откуда я знаю?

  • Вы измерили это?Могу поспорить, что вы этого не сделали, и если бы вы это сделали, вы нашли бы время для форматирования строки крошечным, на порядки меньше, чем время для записи на диск, и близко к времени, которое требуется для вызова функции.

  • Если запись ведется в замкнутом цикле, который вызывается тысячи раз, ваш журнал будет уродливым и сложным в использовании.Так что, держу пари, его там нет или не будет, когда вы закончите отладку.

  • Если ведение журнала не находится в тесном цикле, общее время форматирования потерянных сообщений будет минимальным.

  • Если программа интенсивно использует процессор и тратит много времени на интерпретатор Python, ведение журнала не является причиной.Вам нужно будет найти методы / библиотеки Python, которые облегчают работу интерпретатора, или язык, который это делает.

  • Если бы неправильное использование модуля журнала было серьезной проблемой для многих программистов, в документации были бы предупреждения или исправления в коде.У вас слишком много компании, чтобы самостоятельно обнаружить тривиальную проблему оптимизации.

  • Я видел программы на C, которые используют тяжелые журналы отладки, в которых printf вносит значительные накладные расходы.Но это потому, что остальная часть С такая скудная.Если бы C имел сборку мусора, динамическое разрешение имен, понимание списков и т. Д., Отформатированный ввод-вывод стал бы дешевым.

Самый эффективный способ использования модуля журнала - это способ, который легче всего программировать, потому что ваше время (я надеюсь!) Недешево.Если кто-то жалуется на ваши «потраченные впустую циклы», попросите его показать, как он составляет даже 1% времени работы вашей программы.Тогда вы можете вернуться к чему-то важному.

0 голосов
/ 28 декабря 2018

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

Люди Python предоставляют , как направлять для переключения, либо используя класс-оболочку с __str__ это вызывается только в том случае, если регистрация действительно происходит, или с использованием оболочки LoggerAdapter для подкласса для регистратора, который выполняет ленивое форматирование фигурных скобок (поэтому во время использования вообще никакого лишнего kruft нет).Последний подход является наиболее чистым во время использования.Вот простой пример из руководства:

import logging

class Message(object):
    def __init__(self, fmt, args):
        self.fmt = fmt
        self.args = args

    def __str__(self):
        return self.fmt.format(*self.args)

class StyleAdapter(logging.LoggerAdapter):
    def __init__(self, logger, extra=None):
        super(StyleAdapter, self).__init__(logger, extra or {})

    def log(self, level, msg, *args, **kwargs):
        if self.isEnabledFor(level):
            msg, kwargs = self.process(msg, kwargs)
            self.logger._log(level, Message(msg, args), (), **kwargs)

logger = StyleAdapter(logging.getLogger(__name__))

def main():
    logger.debug('Hello, {}', 'world!')

if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG)
    main()

В реальном коде Message и StyleAdapter, вероятно, будут скрыты в отдельном модуле, оставляя очень мало пользовательского кода в модулях, которые используютим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...