Python: 如何为multiprocessing.Pool中的每一项使用不同的日志文件?

Python: How to use a different logfile for each item in multiprocessing.Pool?

我正在使用 multiprocessing.Pool 到 运行 多个并行的独立任务。与 python 文档中的基本示例没有太大区别:

from multiprocessing import Pool

def f(x):
    return x*x

if __name__ == '__main__':
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))

我希望每个项目都记录到一个单独的文件中。我在我的代码库和一些第三方包中记录来自其他模块的各种信息(none 它们是多处理感知的)。所以,例如,我想要这样:

import logging
from multiprocessing import Pool

def logOnDisk(x):
    logging.info("hello world")

if __name__ == '__main__':
    with Pool() as p:
        p.map(logOnDisk, ["ping", "pong", "foo", "bar"])

写入磁盘:

ping.log
pong.log
foo.log
bar.log

每个文件都应该包含字符串“hello world”。 我该如何实现?

要为工作人员内部的每个已处理项目(您传递给 pool.map() 的可迭代项目)使用单独的日志文件,实际上不需要 multiprocessing-specific。但是你可以 可以使用 Pool 的 initializer() 在 workers 内部设置 root-loggers 并存储一些 meta-data 用于日志记录。在幕后,Pool(initializer)Pool(initargs) 的参数最终被传递给 Process(target)Process(args) 以创建新的 worker-processes。 然后你只需要交换 Filehandler 为每一个在 workers 中用 log_on_disk() 处理的项目。

import logging
import multiprocessing as mp


def log_on_disk(x):
    logger = _init_logger(file_id=x)
    logger.info(f"hello world")


def _init_logging(level=logging.INFO, mode='a'):
    fmt = logging.Formatter(
        '%(asctime)s %(processName)-10s %(name)s %(levelname)-8s --- %(message)s'
    )
    logger = logging.getLogger()
    logger.setLevel(level)
    globals()['_log_meta'] = {'mode': mode, 'fmt': fmt}


def _init_logger(file_id):
    logger = logging.getLogger()
    logger.handlers = []  # remove all handlers
    fh = logging.FileHandler(f"{file_id}.log", mode=_log_meta['mode'])
    fh.setFormatter(_log_meta['fmt'])
    logger.addHandler(fh)
    return logger


if __name__ == '__main__':

    with mp.Pool(5, initializer=_init_logging, initargs=(logging.DEBUG,)) as pool:
       pool.map(log_on_disk, ["ping", "pong", "foo", "bar"])

@Darkonaut 得到了正确的解决方案。我误解了这个问题,因为我认为“日志记录”是一个通用的占位符模块,而不是一个实际的模块。

如果你只想要 dead-simple 方法,那么你可以这样做:

from multiprocessing import Pool

def logOnDisk(x):
    f = open(''.join(x + ".log"), "w+")
    f.write("hello world")
    f.close()

if __name__ == '__main__':
    with Pool() as p:
        p.map(logOnDisk, ["ping", "pong", "foo", "bar"])

您当然可以将 LogOnDisk 的内容移动到日志中或 logging.info:

main.py:

import logging
from multiprocessing import Pool

def logOnDisk(x):
    logging.info(x, "hello world")

if __name__ == '__main__':
    with Pool() as p:
        p.map(logOnDisk, ["ping", "pong", "foo", "bar"])

logging.py:

class info:
    def __init__(self, filename, log_message):
        f = open(''.join(filename + ".log"), "w+")
        f.write(log_message)
        f.close()

进一步细化会得到:

main.py:

from logging import logger
from multiprocessing import Pool

def logOnDisk(x):
    logger_obj = logger(x)
    logger_obj.info("hello world")

if __name__ == '__main__':
    with Pool() as p:
        p.map(logOnDisk, ["ping", "pong", "foo", "bar"])

logging.py:

class logger:
    def __init__(self, filename):
        self.f = open(''.join(filename + ".log"), "w+")

    def __del__(self):
        self.f.close()

    def info(self, logString):
        self.f.write(logString)