You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python logging搭配joblib多线程时日志文件为空的问题

多线程/多进程下logging写入文件为空的问题

问题现象

使用joblib.Parallel开启多任务(n_jobs=4)时,通过logging向文件写入日志,最终得到空文件;但n_jobs=1单线程执行时,日志能正常输出。

复现代码

import logging
import time
from joblib import Parallel, delayed

def worker(index):
    time.sleep(0.5)
    logging.info('Hi from myfunc {}'.format(index))
    time.sleep(0.5)

def main():
    logging.basicConfig(filename='multithread_test.log', level=logging.INFO, format='%(relativeCreated)6d %(threadName)s %(message)s')
    Parallel(n_jobs=4)(delayed(worker)(m) for m in range(1, 8))
    
if __name__ == '__main__':
    main()

单线程正常输出示例

1636 MainThread Hi from myfunc 1
  2656 MainThread Hi from myfunc 2
  3676 MainThread Hi from myfunc 3
  4696 MainThread Hi from myfunc 4
  5716 MainThread Hi from myfunc 5
  6736 MainThread Hi from myfunc 6
  7756 MainThread Hi from myfunc 7

原因分析

joblib.Parallel默认使用loky多进程后端(n_jobs>1时),而logging.basicConfig仅在主线程初始化日志配置,子进程不会继承主线程的日志处理器(handler),导致子进程中的logging.info没有输出目标,日志无法写入文件。

解决方案

方案1:强制使用线程后端

如果任务是IO密集型,适合用多线程,指定backend='threading'后,子线程会继承主线程的日志配置:

def main():
    logging.basicConfig(filename='multithread_test.log', level=logging.INFO, format='%(relativeCreated)6d %(threadName)s %(message)s')
    # 指定线程后端
    Parallel(n_jobs=4, backend='threading')(delayed(worker)(m) for m in range(1, 8))

方案2:子进程中重新初始化日志

若必须用多进程(CPU密集型任务),可在worker函数中重新配置日志:

def worker(index):
    # 子进程内单独初始化日志
    logging.basicConfig(filename='multithread_test.log', level=logging.INFO, format='%(relativeCreated)6d %(threadName)s %(message)s')
    time.sleep(0.5)
    logging.info('Hi from myfunc {}'.format(index))
    time.sleep(0.5)

注意:多进程直接写入同一文件可能出现内容覆盖,建议使用logging.handlers.RotatingFileHandler等多进程安全的处理器,或给每个进程分配独立日志文件。

方案3:全局配置日志处理器

提前创建并配置日志处理器,添加到根logger,确保子进程继承配置:

def main():
    # 创建文件处理器并设置格式
    handler = logging.FileHandler('multithread_test.log')
    formatter = logging.Formatter('%(relativeCreated)6d %(threadName)s %(message)s')
    handler.setFormatter(formatter)
    
    # 配置根logger
    root_logger = logging.getLogger()
    root_logger.setLevel(logging.INFO)
    root_logger.addHandler(handler)
    
    Parallel(n_jobs=4)(delayed(worker)(m) for m in range(1, 8))

内容的提问来源于stack exchange,提问作者Mehmet Fide

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:35:26