Python日志性能优化核心是异步化、延迟格式化、合理分级和批量落盘:用QueueHandler+QueueListener实现零依赖异步,延迟解析msg/args,避免耗时函数入参,按场景选handler,限制日志内容长度并采样输出。

Python 日志性能瓶颈通常出现在高频写入、同步 I/O、格式化开销或不当配置上。关键不是少打日志,而是让日志“不拖慢主线程”——核心思路是异步化、延迟格式化、合理分级和批量落盘。
用 QueueHandler + QueueListener 实现异步日志
这是官方推荐的零依赖异步方案:日志记录器把 LogRecord 放进队列,由独立线程消费并真正写入文件或网络。主线程完全不阻塞。
- 创建 queue.Queue() 实例,作为中转通道
- 主 logger 添加 QueueHandler(queue),它只负责入队,不执行 format 或 write
- 另起一个线程运行 QueueListener(queue, handler1, handler2...),它从队列取记录、格式化、输出
- 注意:handler 必须是线程安全的(如 FileHandler 默认是;自定义 handler 需加锁)
关闭不必要的日志格式化开销
每次调用 logger.info("user %s login", user_id) 时,如果日志等级被过滤掉(比如当前设为 WARNING),默认仍会执行字符串格式化——这在高频场景下浪费 CPU。
- 启用 logging.setLogRecordFactory() 自定义 LogRecord,延迟解析 msg 和 args(仅当真正需要输出时才 format)
- 更简单:直接使用 logger.debug("msg %r", obj) 而非 logger.debug(f"msg {obj}"),前者由 logging 框架控制是否格式化
- 避免在日志参数中调用耗时函数,例如
logger.info("time: %s", expensive_func())—— 它总被执行
按场景选择合适的 handler 和级别
不是所有日志都该写磁盘。高频业务逻辑建议用内存缓冲+定期刷盘,调试类日志可直接丢弃。
立即学习“Python免费学习笔记(深入)”;
- 生产环境慎用 RotatingFileHandler:每次写入都触发系统调用,且 rotate 时可能卡住;改用 TimedRotatingFileHandler 并设置
backupCount=0或配合异步队列 - 对性能极度敏感模块(如实时交易),可先写入 memoryview / bytearray 缓冲区,再由后台线程批量 flush 到文件
- 用 Filter 在 handler 层做二次过滤(如只记录特定用户 ID 的请求),比在每处 logger.info 前加 if 更干净
避免日志内容引发隐式性能问题
日志消息本身可能成为瓶颈,尤其涉及对象序列化、堆栈追踪或大结构体打印。
- 禁止在日志中直接打印 traceback.format_exc() 或 repr(large_dict);改用 logger.exception("msg")(它只在 ERROR 级别才收集 traceback)
- 对长列表、JSON 字符串等,限制长度:
str(obj)[:500] + "...",避免 GC 压力和 I/O 膨胀 - 不要在循环内频繁调用
logger.debug(...);改用计数器聚合后统一输出,或用采样日志(如每 100 次记录一次)











