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秒内调用
答案 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()
在实际代码中,Message
和StyleAdapter
可能会隐藏在单独的模块中,而在使用它们的模块中只保留很少的自定义代码。
答案 1 :(得分:2)
严重的是,您正在担心错误的问题。是的,该字符串将被格式化,并且最终可能会被丢弃。不,没关系。
我怎么知道?
您测量了吗?我敢打赌,如果没有,您会发现格式化字符串的时间很小,比写入磁盘的时间少几个数量级,并且接近于调用函数所花费的时间。
如果日志记录处于紧密的循环中,称为数千次,则您的日志将很丑陋且难以使用。所以我敢打赌它不存在,或者当您完成调试时就不会存在。
如果日志记录不是紧密循环,则丢失消息的总格式化时间将很小。
如果该程序占用大量CPU,并且在Python解释器中花费大量时间,那么记录日志不是原因。您将需要寻找减轻工作解释或工作语言解释能力的Python技术/库。
如果对许多程序员而言,日志模块的滥用是一个严重的问题,则文档中将出现警告或代码已修复。您的公司太多,无法独立发现一个琐碎的优化问题。
我已经看到了使用重型调试日志的C程序,其中 printf 占用了大量的开销。但这是因为C的其余部分太瘦了。如果C具有垃圾回收,动态名称解析和列表理解等功能,则格式化的I / O看起来将变得便宜。
使用日志模块的最有效方法是您最容易编程的方法,因为您的时间(我希望!)并不便宜。如果有人抱怨您的“浪费的周期”,请让他证明它如何占程序运行时间的1%。然后,您可以将精力集中在重要的事情上。