python:多进程池嵌套以及内存管理

前言

在使用进程嵌套进行并行调参的过程中,使用了close关闭进程池,使得创建的进程池中的进程变为stopped状态,造成了内存泄漏,最后导致了内存溢出,最后发现了问题整理了这篇文章。

1.进程池

当创建的子进程数量不多时,可以使用multiprocessing.Process动态创建。但是,当创建的子进程数量很多时,因为创建子进程也需要开销,如果按照上述方面创建,代价较高,因此使用进程池进行创建子进程。另一方面,使用进程池能够最大限度的利用资源。一个CPU能并行的进程数是有限制的,超过这个数量时,进程之间需要进行切换,反而会降低效率。

python中使用multiprocessing.Pool创建进程池

import multiprocessing as mp

def func(i):
	print(i)

if __name__ == "__main__":
	num_cores = 4
	pool = mp.Pool(num_cores)
	for i in range(10):
		pool.map(func, (i, ))
		
	pool.close()
	print("end")

输出:

2
6
0
3
7
1
5
9
4
8
end

map函数,使进程阻塞执行,直到子进程全部结束,才会继续执行主进程。

2. 多进程池嵌套

由于python的GIL(Global Interpreter Lock,即全局解释器锁)存在(参考 python:GIL介绍),对于CPU频繁型的任务,线程并行并不能提高效率。因此,对于进程中如果存在仍需并行的任务时,仍需使用进程并行去解决,这涉及到如何解决进程嵌套问题。

multiprocessing.Pool创建的进程池中的子进程,默认为守护进程(即主进程结束则依赖主进程的子进程也会结束),无法在进程中创建子进程,因此需要修改进程池中子进程的属性。

重构multiprocessing.Pool类

# 重构multiprocessing.Process类,将进程始终定义为非守护进程
class NoDaemonProcess(multiprocessing.Process):
    # make 'daemon' attribute always return False
    def _get_daemon(self):
        return False
    def _set_daemon(self, value):
        pass
    daemon = property(_get_daemon, _set_daemon)
	
# 重构multiprocessing.Pool类
class Pool(multiprocessing.Pool):
    Process = NoDaemonProcess

3. 内存管理

  • 内存溢出和内存泄漏
    内存溢出, 指系统已经无法再分配所需的空间。
    内存泄漏, 指没有回收已经使用过的资源,导致内存没有被释放。当内存泄漏的次数过多时,可能导致内存溢出。

  • pool.close 与 pool.terminate的区别
    close和terminate都能够阻止进程池接受新的请求,但是terminate会中断正在执行的子进程操作,而close不会。terminate会直接注销进程池中创建的子进程,将内存回收,而close则会在主进程正常退出时才会回收资源,若此时发生意外中断了主进程,则close后的进程池中的进程不会被注销,而是会变成stopped状态或者zombie状态,占用的内存资源也无法释放,造成内存泄漏。

  • 3
    点赞
  • 4
    收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 3

打赏作者

yyliunianyy

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值