热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python多进程编程:深入解析与实战技巧

在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 notNone:#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 inactive_children():ifp._daemonic:

info('calling terminate() for daemon %s', p.name)

p._popen.terminate()for p inactive_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.getif hasattr(inqueue, '_writer'):

inqueue._writer.close()

outqueue._reader.close()if initializer is notNone:

initializer(*initargs)

completed=0while maxtasks is None or (maxtasks and completed

task=get()except(EOFError, IOError):

debug('worker got EOFError or IOError -- exiting')break

if task isNone:

debug('worker got sentinel -- exiting')breakjob, i, func, args, kwds=tasktry:

result= (True, func(*args, **kwds))exceptException, e:

result=(False, e)try:

put((job, i, result))exceptException as e:

wrapped= MaybeEncodingError(e, result[1])

debug("Possible encoding error while sending result: %s" %(

wrapped))

put((job, i, (False, wrapped)))

completed+= 1debug('worker exiting after %d tasks' % completed)

worker退出的时候,看如下代码

## process.py

def_bootstrap(self):from . importutilglobal_current_processtry:

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=0finally:

util._exit_function()

子进程run()会结束,然后调用_exit_function()清理一些子进程,调用_run_finalizers()结束进程。

但是如果子进程在pool的worker中跑的是长时间不退出的task,那这个子进程就会无法退出,一直在运行。如果task都是短作业,即使主进程被kill -9,子进程也会在作业跑完之后都退出。



推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.xmlbeans.SchemaType 类的 getBaseEnumType() 方法,提供了多个代码示例,并解释了其在不同场景下的使用方法。 ... [详细]
  • 并发编程:深入理解设计原理与优化
    本文探讨了并发编程中的关键设计原则,特别是Java内存模型(JMM)的happens-before规则及其对多线程编程的影响。文章详细介绍了DCL双重检查锁定模式的问题及解决方案,并总结了不同处理器和内存模型之间的关系,旨在为程序员提供更深入的理解和最佳实践。 ... [详细]
  • 本文详细探讨了JDBC(Java数据库连接)的内部机制,重点分析其作为服务提供者接口(SPI)框架的应用。通过类图和代码示例,展示了JDBC如何注册驱动程序、建立数据库连接以及执行SQL查询的过程。 ... [详细]
  • 本文详细介绍了如何解决Uploadify插件在Internet Explorer(IE)9和10版本中遇到的点击失效及JQuery运行时错误问题。通过修改相关JavaScript代码,确保上传功能在不同浏览器环境中的一致性和稳定性。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文基于刘洪波老师的《英文词根词缀精讲》,深入探讨了多个重要词根词缀的起源及其相关词汇,帮助读者更好地理解和记忆英语单词。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 在 Swift 编程中,遇到错误提示“一元运算符 '!' 不能应用于 '()' 类型的操作数”,通常是因为尝试对没有返回值的方法或函数应用逻辑非运算符。本文将详细解释该错误的原因,并提供解决方案。 ... [详细]
  • 本文详细介绍了中央电视台电影频道的节目预告,并通过专业工具分析了其加载方式,确保用户能够获取最准确的电视节目信息。 ... [详细]
  • 使用Pandas高效读取SQL脚本中的数据
    本文详细介绍了如何利用Pandas直接读取和解析SQL脚本,提供了一种高效的数据处理方法。该方法适用于各种数据库导出的SQL脚本,并且能够显著提升数据导入的速度和效率。 ... [详细]
author-avatar
然姐2502870593
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有