Python: 如何在multiprocessing.Pool中为进程使用不同的日志文件?
Python: How to use different logfiles for processes 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 f(x):
logging.info(f"x*x={x*x}")
return x*x
if __name__ == '__main__':
with Pool(5) as p:
print(p.map(f, range(10)))
写入磁盘:
log1.log
log2.log
log3.log
log4.log
log5.log
如何实现?
您需要使用 Pool 的 initializer()
在工作人员启动后立即设置和注册单独的记录器。在幕后,Pool(initializer)
和 Pool(initargs)
的参数最终被传递给 Process(target)
和 Process(args)
以创建新的 worker-processes...
Pool-workers 以 {start_method}PoolWorker-{number} 格式命名,例如SpawnWorker-1
如果您使用 spawn 作为新进程的启动方法。
然后可以使用 mp.current_process().name.split('-')[1]
.
从分配的 worker-names 中提取日志文件的文件编号
import logging
import multiprocessing as mp
def f(x):
logger.info(f"x*x={x*x}")
return x*x
def _init_logging(level=logging.INFO, mode='a'):
worker_no = mp.current_process().name.split('-')[1]
filename = f"log{worker_no}.log"
fh = logging.FileHandler(filename, mode=mode)
fmt = logging.Formatter(
'%(asctime)s %(processName)-10s %(name)s %(levelname)-8s --- %(message)s'
)
fh.setFormatter(fmt)
logger = logging.getLogger()
logger.addHandler(fh)
logger.setLevel(level)
globals()['logger'] = logger
if __name__ == '__main__':
with mp.Pool(5, initializer=_init_logging, initargs=(logging.DEBUG,)) as pool:
print(pool.map(f, range(10)))
请注意,由于多处理的性质,无法保证您在小示例中最终得到的文件的确切数量。
由于 multiprocessing.Pool
(与 concurrent.futures.ProcessPoolExecutor
相反)在您创建实例后立即启动工作程序,因此您一定会获得指定的 Pool(process)
- 文件数,因此在您的情况下为 5. 实际thread/process-scheduling 你的 OS 可能会在这里缩短这个数字。
我正在使用 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 f(x):
logging.info(f"x*x={x*x}")
return x*x
if __name__ == '__main__':
with Pool(5) as p:
print(p.map(f, range(10)))
写入磁盘:
log1.log
log2.log
log3.log
log4.log
log5.log
如何实现?
您需要使用 Pool 的 initializer()
在工作人员启动后立即设置和注册单独的记录器。在幕后,Pool(initializer)
和 Pool(initargs)
的参数最终被传递给 Process(target)
和 Process(args)
以创建新的 worker-processes...
Pool-workers 以 {start_method}PoolWorker-{number} 格式命名,例如SpawnWorker-1
如果您使用 spawn 作为新进程的启动方法。
然后可以使用 mp.current_process().name.split('-')[1]
.
import logging
import multiprocessing as mp
def f(x):
logger.info(f"x*x={x*x}")
return x*x
def _init_logging(level=logging.INFO, mode='a'):
worker_no = mp.current_process().name.split('-')[1]
filename = f"log{worker_no}.log"
fh = logging.FileHandler(filename, mode=mode)
fmt = logging.Formatter(
'%(asctime)s %(processName)-10s %(name)s %(levelname)-8s --- %(message)s'
)
fh.setFormatter(fmt)
logger = logging.getLogger()
logger.addHandler(fh)
logger.setLevel(level)
globals()['logger'] = logger
if __name__ == '__main__':
with mp.Pool(5, initializer=_init_logging, initargs=(logging.DEBUG,)) as pool:
print(pool.map(f, range(10)))
请注意,由于多处理的性质,无法保证您在小示例中最终得到的文件的确切数量。
由于 multiprocessing.Pool
(与 concurrent.futures.ProcessPoolExecutor
相反)在您创建实例后立即启动工作程序,因此您一定会获得指定的 Pool(process)
- 文件数,因此在您的情况下为 5. 实际thread/process-scheduling 你的 OS 可能会在这里缩短这个数字。