无需在子进程函数内初始化,如何抑制joblib并行的打印输出?
问题出在joblib默认的多进程并行机制上——主进程的contextlib.redirect_stdout仅修改了自身的sys.stdout对象,而子进程作为独立进程,启动时会继承父进程初始的标准输出文件描述符,而非主进程临时重定向后的sys.stdout引用,所以子进程的打印会绕过主进程的重定向。
以下是两种无需修改并行任务函数的解决方法:
方法一:切换为线程并行backend
线程与主进程共享内存空间和文件描述符,主进程的stdout重定向会直接作用于所有线程。只需给Parallel添加backend='threading'参数:
from joblib import Parallel, delayed import os import contextlib def start(): print('HELLO') def para(i): print('hello') # 指定线程backend a = Parallel(n_jobs=2, backend='threading')(delayed(para)(i) for i in [0,1,2]) with contextlib.redirect_stdout(open(os.devnull, "w")): start()
⚠️ 注意:如果你的任务是CPU密集型,线程backend会受GIL限制导致并行效率低下,这种情况不建议使用。
方法二:底层文件描述符重定向
直接操作标准输出的文件描述符,这种方式对多进程、线程都有效,因为子进程会继承父进程的文件描述符:
from joblib import Parallel, delayed import os import sys def start(): print('HELLO') def para(i): print('hello') a = Parallel(n_jobs=2)(delayed(para)(i) for i in [0,1,2]) # 保存原始stdout的文件描述符 old_stdout_fd = os.dup(sys.stdout.fileno()) try: # 将stdout重定向到/dev/null with open(os.devnull, 'w') as null_file: os.dup2(null_file.fileno(), sys.stdout.fileno()) start() finally: # 恢复原始stdout,避免影响后续操作 os.dup2(old_stdout_fd, sys.stdout.fileno()) os.close(old_stdout_fd)
这种方法不限制并行backend的选择,同时能彻底屏蔽所有进程的打印输出,是通用性最强的方案。
内容的提问来源于stack exchange,提问作者Noob Programmer
相关产品推荐
相关产品推荐

