在多处理上下文中混淆Python日志记录模块的行为

时间:2014-07-19 14:05:47

标签: python python-2.7 logging multiprocessing

所以我想在logging上下文中使用multiprocessing。假设我想让每个进程编写自己的日志文件。这是我的设置:

# worker.py
import logging
import os

def worker( x ) :
    """
    Write the value of x in the log file
    """
    logger = logging.getLogger( __name__ )
    pid = os.getpid() # get the process id
    handler = logging.FileHandler( str(pid) + ".log" )  
    logger.addHandler( handler )
    logger.info( "pid={pid}, x={x}".format( **locals() ) )

这是我的main

import logging
import multiprocessing as mp
import worker

# logger
logger = logging.getLogger()
logger.setLevel( logging.INFO )

# handler
handler = logging.FileHandler( 'main.log' )
logger.addHandler( handler )

#
if __name__ == '__main__' :
    pool = mp.Pool( processes=2 )
    pool.map( worker.worker, range(5) )
    pool.close()
    pool.join()

现在输出日志文件。这是main.log

pid=1985, x=0
pid=1985, x=2
pid=1986, x=1
pid=1985, x=3
pid=1986, x=4

我认为此输出是正常的:两个子进程将事件传播到根父级。所以对应Logging to a single file from multiple processes场景(是吗?)。但现在这是第一个子进程日志文件:

pid=1985, x=0
pid=1985, x=2
pid=1985, x=2
pid=1985, x=3
pid=1985, x=3
pid=1985, x=3

这是第二个子日志文件:

pid=1986, x=1
pid=1986, x=4
pid=1986, x=4

看起来每个子进程为第一次输入写入一次日志,为第二次输入写入两次,为第三次输入写入三次等等。发生了什么事?

1 个答案:

答案 0 :(得分:4)

这种情况正在发生,因为每次您输入worker时,您都会获得对同一logger个对象的引用,然后向其添加新的FileHandler。因此,如果worker被调用三次,则其logger最终会有三个FileHandlers,这些都会写入同一个文件。您应该使用initializer关键字参数在启动时在每个Pool进程中设置记录器:

def init( ) :
    logger = logging.getLogger( __name__ )
    pid = os.getpid() # get the process id
    handler = logging.FileHandler( str(pid) + ".log" )  
    logger.addHandler( handler )

然后像这样启动游泳池

 p = multiprocessing.Pool(processes=2, initializer=init)

然后,工作人员可以抓住logger对象并使用它而不向其添加FileHandler