python multiprocessing深度解析
在写python多线程代码的时候,会用到multiprocessing这个包,这篇文章总结了一些这个包在多进程管理方面的一些原理和代码分析。
1. 问题一:是否需要显式调用pool的close和join方法,不调用的话,子进程是否无法退出?
首先初始化Pool的时候,指定processes的个数,就是pool中worker的个数,pool初始化的时候,会把worker以daemon=True的子进程方式启动起来。
def _repopulate_pool(self):
"""Bring the number of pool processes up to the specified number,
for use after reaping workers which have exited.
"""
for i in range(self._processes - len(self._pool)):
w = self.Process(target=worker,
args=(self._inqueue, self._outqueue,
self._initializer,
self._initargs, self._maxtasksperchild)
)
self._pool.append(w)
w.name = w.name.replace('Process', 'PoolWorker')
w.daemon = True
w.start()
debug('added worker')
推荐在使用完pool之后,用thread pool的时候调用close()和join()方法,这样可以把pool中的worker都释放掉(等待子任务结束)。但是如果不显式的调用,在主进程退出的时候,这些子进程也会退出(原因是设置了daemon这个flag)。
def _exit_function(info=info, debug=debug, _run_finalizers=_run_finalizers,
active_children=active_children,
current_process=current_process):
# NB: we hold on to references to functions in the arglist due to the
# situation described below, where this function is called after this
# module's globals are destroyed. global _exiting info('process shutting down')
debug('running all "atexit" finalizers with priority >= 0')
_run_finalizers(0) if current_process() is not None:
# NB: we check if the current process is None here because if
# it's None, any call to ``active_children()`` will throw an
# AttributeError (active_children winds up trying to get
# attributes from util._current_process). This happens in a
# variety of shutdown circumstances that are not well-understood
# because module-scope variables are not apparently supposed to
# be destroyed until after this function is called. However,
# they are indeed destroyed before this function is called. See
# issues 9775 and 15881. Also related: 4106, 9205, and 9207. for p in active_children():
if p._daemonic:
info('calling terminate() for daemon %s', p.name)
p._popen.terminate() for p in active_children():
info('calling join() for process %s', p.name)
p.join() debug('running the remaining "atexit" finalizers')
_run_finalizers()
主进程退出的时候,会调用_exit_function, 如果看到active的children是_daemonic的就会调用其terninate方法,让子进程退出。exit是通过这个调用注册的,atexit.register(_exit_function),本质是利用系统的退出hook方法,在退出的时候触发对应的函数。
2. 问题二:如果启动之后,kill -9主进程,子进程会不会无法退出?
如下代码是pool中worker的主代码逻辑,如果kill -9主进程,子进程如果没有在处理作业,因为主进程退出了,get()方法从queue中拿task的时候,就会发生exception,这样worker会退出。如果子进程正在处理任务,任务结束的时候,需要往queue中扔回结果,因为主进程退出了,所以也会exception,worker一样会退出。
def worker(inqueue, outqueue, initializer=None, initargs=(), maxtasks=None):
assert maxtasks is None or (type(maxtasks) == int and maxtasks > 0)
put = outqueue.put
get = inqueue.get
if hasattr(inqueue, '_writer'):
inqueue._writer.close()
outqueue._reader.close() if initializer is not None:
initializer(*initargs)
completed = 0
while maxtasks is None or (maxtasks and completed < maxtasks):
try:
task = get()
except (EOFError, IOError):
debug('worker got EOFError or IOError -- exiting')
break if task is None:
debug('worker got sentinel -- exiting')
break job, i, func, args, kwds = task
try:
result = (True, func(*args, **kwds))
except Exception, e:
result = (False, e)
try:
put((job, i, result))
except Exception as e:
wrapped = MaybeEncodingError(e, result[1])
debug("Possible encoding error while sending result: %s" % (
wrapped))
put((job, i, (False, wrapped)))
completed += 1
debug('worker exiting after %d tasks' % completed)
worker退出的时候,看如下代码
## process.py
def _bootstrap(self):
from . import util
global _current_process try:
self._children = set()
self._counter = itertools.count(1)
try:
sys.stdin.close()
sys.stdin = open(os.devnull)
except (OSError, ValueError):
pass
_current_process = self
util._finalizer_registry.clear()
util._run_after_forkers()
util.info('child process calling self.run()')
try:
self.run()
exitcode = 0
finally:
util._exit_function()
子进程run()会结束,然后调用_exit_function()清理一些子进程,调用_run_finalizers()结束进程。
但是如果子进程在pool的worker中跑的是长时间不退出的task,那这个子进程就会无法退出,一直在运行。如果task都是短作业,即使主进程被kill -9,子进程也会在作业跑完之后都退出。
python multiprocessing深度解析的更多相关文章
- 深度解析:python之浅拷贝与深拷贝
深度解析python之浅拷贝与深拷贝 本文包括知识点: 1.copy与deepcopy 2.可变类型与不可变类型 1.copy与deepcopy 在日常python编码过程中,经常会遇见变量的赋值.这 ...
- python MultiProcessing模块进程间通信的解惑与回顾
这段时间沉迷MultiProcessing模块不能自拔,没办法,python的基础不太熟,因此就是在不断地遇到问题解决问题.之前学习asyncio模块学的一知半解,后来想起MultiProcessin ...
- Go netpoll I/O 多路复用构建原生网络模型之源码深度解析
导言 Go 基于 I/O multiplexing 和 goroutine 构建了一个简洁而高性能的原生网络模型(基于 Go 的I/O 多路复用 netpoll),提供了 goroutine-per- ...
- [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析
[WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285 ...
- 第37课 深度解析QMap与QHash
1. QMap深度解析 (1)QMap是一个以升序键顺序存储键值对的数据结构 ①QMap原型为 class QMap<K, T>模板 ②QMap中的键值对根据Key进行了排序 ③QMap中 ...
- Deep Learning模型之:CNN卷积神经网络(一)深度解析CNN
http://m.blog.csdn.net/blog/wu010555688/24487301 本文整理了网上几位大牛的博客,详细地讲解了CNN的基础结构与核心思想,欢迎交流. [1]Deep le ...
- (转载)(收藏)OceanBase深度解析
一.OceanBase不需要高可靠服务器和高端存储 OceanBase是关系型数据库,包含内核+OceanBase云平台(OCP).与传统关系型数据库相比,最大的不同点, 是OceanBase是分布式 ...
- Kafka深度解析
本文转发自Jason’s Blog,原文链接 http://www.jasongj.com/2015/01/02/Kafka深度解析 背景介绍 Kafka简介 Kafka是一种分布式的,基于发布/订阅 ...
- java内存分配和String类型的深度解析
[尊重原创文章出自:http://my.oschina.net/xiaohui249/blog/170013] 摘要 从整体上介绍java内存的概念.构成以及分配机制,在此基础上深度解析java中的S ...
随机推荐
- Java容器-个人整理1
1.初始化集合时,若能知道知道容量,尽量初始化时确定容量.容器类一般可以自动扩充,但扩充是有性能代价的. 2.Arrays.asList()的底层表示仍然时数组,因此不能进行调整尺寸的操作. 3.Ha ...
- asp.net core部署到iis中出现 HTTP Error 502.5 - Process Failure的问题
环境是windows Server2012 问题的原因是缺少文件:api-ms-win-crt-runtimel1-1-0.dll, dotnet 启动程序失败. 解决方案1: 安装系统补丁: 20 ...
- Chapter5_初始化与清理_成员初始化
在java中,成员初始化在使用之前应该都要保证已经完成初始化.对于在方法体中的局部变量,如果没有使用指定初始化的方法对成员变量进行初始化,编译器会提示一个错误.而对于类的数据成员,编译器会对这些成员赋 ...
- Spring Boot不同版本整合Redis的配置
1. Spring Boot为1.4及其他低版本 1.1 POM.XML配置 <!--引入 spring-boot-starter-redis(1.4版本前)--> <depende ...
- 人工智能&物联网开发的目录
走进嵌入式开发的世界,企业级项目课程让你达到企业嵌入式应用开发要求.名师在线答疑,解决疑难.科学评测体系,系统评估学习.核心项目实........ 30 门课程 241小时12分钟 824 人学习 学 ...
- 配置Tomcat时遇到的问题
今天准备开始JavaWeb的学习,先配置tomcat,前期一切顺利,可当我打开startup.bat,访问localhost:8080时,却显示localhost 拒绝了我们的连接请求. 于是我开始在 ...
- 环境搭建文档——Windows下的Python3环境搭建
前言 背景介绍: 自己用Python开发了一些安卓性能自动化测试的脚本, 但是想要运行这些脚本的话, 本地需要Python的环境. 测试组的同事基本都没有安装Python环境, 于是乎, 我就想直接在 ...
- 【慕课网实战】七、以慕课网日志分析为例 进入大数据 Spark SQL 的世界
用户: 方便快速从不同的数据源(json.parquet.rdbms),经过混合处理(json join parquet), 再将处理结果以特定的格式(json.parquet)写回到 ...
- .Net QQ互联教程
qq互联只需要备案即可申请,申请成功后可以到qq互联官网查看教程,本站开始想使用js的教程但是由于本站需要绑定本站的账号用js教程无法完成,所以使用原始的oauth2.0来完成. 申请qq互联接口 q ...
- 下划线“_”在oracle中不是单纯的表示下划线的意思,而是表示匹配单一任何字符!
[解决办法]1.使用 escape() 函数escape关键字经常用于使某些特殊字符,如通配符:'%','_'转义为它们原来的字符的意义,被定义的转义字符通常使用'\',但是也可以使用其他的符号.例如 ...