Python如何在multiprocessing.Pool内并行函数 解决守护进程无法创建子进程报错
报错本质
daemonic processes are not allowed to have children
Pythonmultiprocessing模块默认创建的Pool子进程为守护进程,系统约束守护进程不允许再派生自己的子进程,防止孤儿进程泄露。你当前场景中emcee外层Pool的子进程是守护进程,若想在后验函数logp内部再开并行,直接嵌套创建Pool就会触发该报错。
可行解决方案
方案1:取消嵌套并行,优化并行粒度
嵌套多进程会带来额外的进程调度、IPC通信开销,很多时候反而会抵消并行收益。你可以先测试外层Pool跑满时的CPU利用率,如果已经接近100%,内层不需要再加并行,仅优化
logp内部的串行计算即可,比如用numpy向量化替换循环,或者提前预计算可以复用的参数。方案2:自定义非守护进程的外层Pool
可以自己实现支持非守护进程的Pool,替换默认的multiprocessing.Pool传入emcee,这样外层子进程就有权限再创建子进程:
import multiprocessing import multiprocessing.pool # 自定义非守护进程类 class NoDaemonProcess(multiprocessing.Process): # 强制daemon属性为False @property def daemon(self): return False @daemon.setter def daemon(self, value): pass # 自定义非守护进程池 class NoDaemonPool(multiprocessing.pool.Pool): Process = NoDaemonProcess替换原有外层Pool即可:
with NoDaemonPool() as pool: sampler = emcee.EnsembleSampler(nwalkers, npars, logp, pool=pool)方案3:内层用多线程替代多进程
如果你的
Integrand是基于scipy/numpy等已经释放GIL的数值库实现,内层用多线程并行完全可以达到和多进程一样的性能,而且不受守护进程的约束,改造成本最低:from concurrent.futures import ThreadPoolExecutor def logp(p): mu_imf, mu_h0, sigma_h, b_h = p # 封装单个样本的计算逻辑 def calc_i(i): return np.log(quad(lambda m_halo: Integrand(m_halo, i, mu_imf, mu_h0, sigma_h, b_h), 11.9, 15.0107)[0]) # 线程池并行执行循环,max_workers按核心数调整不要超配 with ThreadPoolExecutor(max_workers=4) as executor: logpost = list(executor.map(calc_i, range(ngal))) return np.sum(logpost)
注意事项
不管用哪种嵌套并行方案,都要保证总并发数(外层进程数 * 内层线程/进程数)不超过CPU物理核心数,否则会因为频繁上下文切换导致性能大幅下降。
内容的提问来源于stack exchange,提问作者havij farangi
相关产品推荐
相关产品推荐

