Python-使用.format记录是否会产生额外的CPU周期

时间:2018-12-27 21:43:55

标签: python python-3.x logging

var lists = data.map(l => { return new ListModel(l.listId, l.listName, 'todo'); });

test.py

我上面有以下代码。

当我使用import logging # V1 logging.debug('%s before you %s', 'Look', 'leap!') # V2 logging.debug('{} before you {}'.format('Look', 'leap!')) 执行时,V2是否会导致额外的CPU周期,因为它将首先格式化字符串,然后由于调试级别而不会输出任何内容。

反正有没有在日志中使用python test.py --log=INFO样式并且如果最终没有输出日志又不会招致这个额外的CPU周期?

编辑: 第1部分->是的,通过此测试代码,它是正确的(尽管很小)

.format

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!')) -> 500464函数在0.176秒内调用

python -m cProfile ~/Desktop/old-format.py-> 600464函数在0.237秒内调用

2 个答案:

答案 0 :(得分:5)

是的,当您以这种方式进行操作时,它必须做额外的工作,创建永远不会使用的字符串。就是说,一个小的黑客程序将使您可以切换到延迟格式的邮件。

尽管如此,Python人士还是提供了how to guide来进行切换,方法是将包装器类与__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()

在实际代码中,MessageStyleAdapter可能会隐藏在单独的模块中,而在使用它们的模块中只保留很少的自定义代码。

答案 1 :(得分:2)

严重的是,您正在担心错误的问题。是的,该字符串将被格式化,并且最终可能会被丢弃。不,没关系。

我怎么知道?

  • 您测量了吗?我敢打赌,如果没有,您会发现格式化字符串的时间很小,比写入磁盘的时间少几个数量级,并且接近于调用函数所花费的时间。

  • 如果日志记录处于紧密的循环中,称为数千次,则您的日志将很丑陋且难以使用。所以我敢打赌它不存在,或者当您完成调试时就不会存在。

  • 如果日志记录不是紧密循环,则丢失消息的总格式化时间将很小。

  • 如果该程序占用大量CPU,并且在Python解释器中花费大量时间,那么记录日志不是原因。您将需要寻找减轻工作解释或工作语言解释能力的Python技术/库。

  • 如果对许多程序员而言,日志模块的滥用是一个严重的问题,则文档中将出现警告或代码已修复。您的公司太多,无法独立发现一个琐碎的优化问题。

  • 我已经看到了使用重型调试日志的C程序,其中 printf 占用了大量的开销。但这是因为C的其余部分太瘦了。如果C具有垃圾回收,动态名称解析和列表理解等功能,则格式化的I / O看起来将变得便宜。

使用日志模块的最有效方法是您最容易编程的方法,因为您的时间(我希望!)并不便宜。如果有人抱怨您的“浪费的周期”,请让他证明它如何占程序运行时间的1%。然后,您可以将精力集中在重要的事情上。