multiprocessing解析(二):Pool解析

前面一篇已经把multiprocessing.Process这个最基础的类给解剖了,接下来的这篇就是整个multiprocessing中最重要的类Pool的浅析了,因为如果把Pool的所有方方面面都顾及到的话篇幅会比较长,所以我只会把Pool的整体框架整理一下,细节的内容可以更多的去阅读源码。
1. multiprocessing.Pool的几个参数的解读
Pool的构造参数中有三个我认为比较有用的,先给大家介绍一下。processes表示的是进程池pool中进程个数,如果没有指定那就是调用multiprocessing.get_cpu()获得cpu个数作为processesinitializer是在初始化pool中的worker的时候调用的初始化函数,例如你每一个worker需要连接数据库,那么你可以在initializer中去做这件事,这样每一个worker的数据库连接都是独立的。maxtasksperchild是指每一个worker最多被重复调用的次数,例如maxtasksperchild = 3则表示pool中的worker最多能处理3次任务,然后就会被销毁,然后再重新初始化一个worker,如果你认为你的worker可能会存在内存泄露的可能那么你可以把maxtasksperchild设置成一个合理的值,这样就避免worker一直存活导致内存一直增长。
2. 核心流程图
multiprocessing.Pool中涉及到三个核心队列和三个核心的线程,如果用文字来描述可能会比较枯燥,我就大致的画了一张这些对象之间的关系图:
这里写图片描述
3. multiprocessing.Pool的初始化
在初始化阶段主要做了如下的几件事:
一、初始化队列,就是上文提到的_taskqueue_outqueue_inqueue,作用不再赘述。
二、调用_repopulate_pool()生成pool中的worker(multiprocessing.Process对象),生成的worker设置了daemon属性,保证在主进程退出的时候pool中的worker也都会退出。
三、依次生成_handle_worker_handle_taks_handle_result三个线程,功能在上文中大致有所了解,后面我会把这三个线程的主要功能在详细讲解。
四、实例化multiprocessing.util.Finalize对象,这个类我们在前面的文章中讲过了,就是在_finalizer_registry这个全局字典中加入一个对象,在_exit_function()中执行。当我们手动执行pool.terminate()或者主进程退出的时候会执行这个清理函数。
4. Pool中的worker源码解析
在pool初始化的时候调用Pool._maintain_pool()->Pool._repopulate_pool()->worker()来生成进程池中的worker,首先是调用initializer()初始化函数来进行一次初始化,接着就是在while循环中有条件的循环接收任务并执行,这里的条件就是如果传入了maxtasks(也即是我们之前提到的Pool的初始化参数maxtasksperchild),那么while循环最多接收、执行maxtasks个任务,然后退出。worker从_inqueue接收任务,执行完之后把结果传入_outqueue。哦,对了,worker在收到一个sentinel任务的时候也会退出,在前面我们注册的Finalize对象中就会给每一个worker发送一个sentinel任务。
5._handle_tasks线程
_taskqueue队列中获取任务,然后再转发给_inqueue,然后worker再从_inqueue获得任务执行。那么是谁把任务发送到_taskqueue队列中的呢?当我们调用apply_async()map_async()的时候就会往_taskqueue队列传入任务。
apply_async()中会生成一个代表运行结果的ApplyResult对象,然后在pool对象中_cache列表保存了每一个任务对应的ApplyResult对象,在后面的_handle_results部分我们会看到就是通过_cache获得对应任务的ApplyResult对象,然后调用ApplyResult._set()来返回任务的执行结果。
如果收到了_handle_workers线程发来的结束sentinel,那么_handle_tasksfor循环就会结束,然后给_handle_results线程、pool中的所有worker都发送结束sentinel。
6. _handle_workers线程
就是保持进程pool中能一直保持固定个数的worker,在上面的worker中我们看到一个worker有可能会退出(当然worker异常也可能会退出),那么在_handle_workers线程就会join它,然后再重新生成一个worker加入pool中。当我们terminate pool(_terminate_pool())的时候会把_handle_workers线程的状态设置成TERMINATE,这样_handle_workers线程while循环退出,然后给上面的_handle_tasks线程发送结束sentinel。
7. _handle_results线程
_outqueue中获取已经结束的任务,然后设置任务对应的ApplyResult的结果。
8. terminate函数
有两种情况我们会调用_terminate_pool(),一个就是我们调用pool.terminate(),另外一个就是主进程运行结束_exit_function()->_finalizer_registry->_terminate_pool()。虽然我们看到最终会调用_terminate_pool()函数,但是其实真正做清理工作的是这一行代码worker_handle._state = TERMINATE,真正触发了一系列的terminate。
这里写图片描述
9. multiprocessing.Pool的主要内容就介绍到这里,还包含一些其它的功能函数,基本能从代码中了解到实现原理。

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: `multiprocessing.pool.Pool` 是 Python多进程编程库 `multiprocessing` 中的一个类,用于简化多进程编程的过程。该类提供了一个简单的方法来并行地执行多个任务,它可以通过多个进程(通常是 CPU 核心数量)同时处理任务,从而提高程序的执行效率。 ### 回答2: multiprocessing.pool.PoolPython中的一个模块,它提供了一种简单的方式来并行执行多个进程。 Pool类可以用于创建一个进程池,这个进程池可以管理多个工作进程,从而实现并行计算。通过将任务分配给进程池中的多个进程来同时执行,可以显著提高程序的执行效率。 当我们需要对某个函数进行大量重复计算或者需要进行大规模的数据处理时,使用Pool类可以将这些任务分配给多个进程来同时执行,从而节省时间。 Pool类的主要方法有map()和apply_async()。map()方法可以将一个可迭代对象中的元素按照指定的函数进行计算,并返回计算结果的列表。apply_async()方法可以异步地传递单个任务给进程池中的一个进程,并返回一个AsyncResult对象。 使用Pool类时,可以通过设置进程池的大小来控制并行执行的进程数量。一般来说,进程池的大小应该根据计算机的CPU核心数来确定,以达到最佳的计算效果。 需要注意的是,在使用Pool类时,要确保被传递给进程池中的函数是可以独立执行的,即不依赖于其他全局变量或状态。此外,如果需要使用共享状态或共享内存,可以使用multiprocessing模块中的其他类和方法。 总之,multiprocessing.pool.PoolPython中用于并行计算的一个强大工具,能够有效地提高程序的执行效率。通过将多个任务分配给进程池中的多个进程来同时执行,可以充分利用计算机资源,减少计算时间,提高工作效率。 ### 回答3: multiprocessing.pool.PoolPython标准库中的一个类,用于实现进程池的功能。进程池是一种并发执行任务的方式,它通过预先创建一定数量的子进程,并维护一个任务队列来实现任务的并发执行。 创建一个进程池可以通过Pool类的构造方法来完成,参数通常包括进程池的大小、初始化函数等。进程池创建后,可以使用其提供的方法来向任务队列中添加任务,并且进程池会自动安排空闲的子进程来执行任务。任务的执行结果可以通过返回值或回调函数来获取。 进程池的好处是可以充分利用多核CPU的性能,提高程序的执行效率。同时,进程池的使用也可以简化任务的管理和调度,使得代码更加简洁易懂。 然而,进程池也有一些要注意的地方。首先,进程池在创建时需要占用一定的系统资源,特别是如果进程池的大小设置过大,可能会导致系统负载过高。其次,进程池中的任务是并发执行的,因此需要注意线程安全的问题,如共享资源的同步与互斥。 总结来说,multiprocessing.pool.Pool是一个方便实现进程池的工具类,可以用于提高并发执行任务的效率。仔细使用该类可以充分发挥多核CPU的潜力,但也需要注意资源占用和线程安全的问题。

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值