前言:
  最近帮朋友review其模块服务代码, 使用的是python的twisted网络框架. 鉴于之前并没有使用过, 于是决定好好研究一番.
  不过这个问题, 和twisted网络框架本身没有关系, 而是为了提升QPS性能, 引入了多进程模型而遇到的一个奇怪问题.
  本文将讲述python的多进程机制, 以及atexit的清理函数机制. 权作python的学习笔记.

场景构造:
  具体的业务代码可以简化为如下所述:
  父进程开启多个常驻子进程后, 安然"退休"并结束运行.
  进程的创建借助multiprocessing模块来实现, 其使用方式如thread管理接口相仿.
  编辑python代码文件 subproc_sample.py:

#! /usr/bin/python
#-*- coding: UTF-8 -*- import time
import multiprocessing # 子进程业务逻辑
def proc_func():
while True:
time.sleep(1) if __name__ == "__main__":
# 创建4个子进程
for i in range(4):
# 创建子进程并启动
p = multiprocessing.Process(target=proc_func, args=())
p.start()
# 父进程安然退出

  该样例中, 父进程创建4个子进程后, 就Do nothing, 安然退出了(预期中).
  然后事实却不如此, 我们借助 ps 命令过滤后发现, 父进程和4个子进程都活着, 如下图所示:
  
  这中间有何玄机呢? 父进程为何不按常理出牌呢?

问题追踪:
  "工欲善其事, 必先利其器", 我们借助pstack来查看下父进程(python底层是用c/c++编写)为何不退出.
  命令: pstack <pid>, pid为父进程id.

  从堆栈的顶层可以看到, 父进程阻塞在waitpid系统调用. 看来父进程在等待子进程的正常退出.
  令一方面, 从堆栈中, 我们可以发现, 此时父进程已在python主程序退出之后, 其做了清理工作Py_Finalize.
  这让我们联想到unix c中提到atexit退出清理机制.
  python是否也有类似的机制, 可以注册程序的退出清理函数.
  我们把父进程切换到前台运行, fg之后, ctrl+c挂掉父进程.
  
  从中可以看到atexit.py, 由此可见, 我们的猜测并没有错.

  
  在/usr/lib64/python2.6/multiprocessing/util.py中, 我们可以找到注册的时间点, 还有注册的函数_exit_function, 该函数完成了父进程对子进程的wait操作.
  

总结:
  python的多线程设计的非常的巧妙, 使得创建/使用多进程,如同多线程使用那样方便和简洁. 当然python背后也封装添加了一些额外的工作, 这些工作可能会有悖于Unix开发者的常规想法. 当然任何诡异的现象, 背后一定有迹可循.

写在最后:
  
如果你觉得这篇文章对你有帮助, 请小小打赏下. 其实我想试试, 看看写博客能否给自己带来一点小小的收益. 无论多少, 都是对楼主一种由衷的肯定.

  

多进程和atexit清理函数的更多相关文章

  1. POSIX 线程清理函数

    POSIX 多线程的 cleanup 函数 控制清理函数的函数有两个,一个是 pthread_cleanup_push(), 用来把清理函数压入栈中,另一个是 pthread_cleanup_pop( ...

  2. linux清理函数

    每个非试验性的模块也要求有一个清理函数, 它注销接口, 在模块被去除之前返回所有资 源给系统. 这个函数定义为: static void   exit cleanup_function(void) { ...

  3. C/C++网络编程7——多进程服务器端之fork函数

    通过前面几节的内容,我们已经可以实现基本的C/S结构的程序了,但是当多个客户端同时向服务器端请求服务时,服务器端只能按顺序一个一个的服务,这种情况下,客户端的用户是无法忍受的.所以虚实现并发的服务器端 ...

  4. Linux下多进程编程之exec函数语法及使用实例

    exec函数族 1)exec函数族说明 fork()函数用于创建一个子进程,该子进程几乎复制了父进程的全部内容,但是,这个新创建的进程如何执行呢?exec函数族就提供了一个在进程中启动另一个程序执行的 ...

  5. 深入浅出--UNIX多进程编程之fork()函数

    0前言 上周都在看都在学习unix环境高级编程的第八章--进程控制.也就是这一章中.让我理解了unix中一些进程的原理.以下我就主要依照进程中最重要的三个函数来进行解说.让大家通过阅读这一篇文章彻底明 ...

  6. 多进程编程之system()函数

    1.system函数: 使用函数system,在程序中执行一个shell命令字符串很方便.它是一个和操作系统紧密相关的函数,用户可以使用它在自己的程序中调用系统提供的各种命令,执行系统的命令行,其实也 ...

  7. Creo二次开发--内存清理函数

    我们在处理模型文件时,总会遇到内存环境的清除问题.一个干净的Creo工作环境.是保证工作能顺利完毕的保障. ProMdlEraseNotDisplayed()函数提供了清除未显示模型的功能. 当须要循 ...

  8. atexit注册的函数是在main函数之后执行?

    跟atexit函数相识已久,man手册里对atexit的解释是这么一段: The atexit() function registers the given function to be called ...

  9. 回收进程用户空间资源 exit()函数 _exit()函数 atexit()函数 on_exit()函数

    摘要:本文主要讲述进程的终止方式,以及怎样使用exit()函数来终止进程.回收进程用户空间资源:分析了exit()函数与_exit()函数,returnkeyword的差异.同一时候具体解读了怎样使用 ...

随机推荐

  1. jsm使用

    参考:http://blog.csdn.net/robinjwong/article/details/38820259

  2. [css]邮件的写法

    <style type="text/css">        /* Client-specific Styles */        #outlook a{paddin ...

  3. PHPExcel 学习笔记

    首先到phpexcel官网上下载最新的phpexcel类,下周解压缩一个classes文件夹,里面包含了PHPExcel.php和PHPExcel的文件夹,这个类文件和文件夹是我们需要的,把class ...

  4. 创建一个ROS msg

    1. msg •msg:msg文件是简单的文本文件,用于描述ROS中消息(消息的各个参数项).用于为不同的编程语言生成有关消息的源代码. •srv:描述服务的文件,由两部分组成:请求和反馈: msg文 ...

  5. dedecms二级菜单实现

    修改channelartlist.lib.php if($typeid==0 || $typeid=='top') { $tpsql = " reid=0 AND ispart<> ...

  6. (DFS)hdoj1198-Farm Irrigation

    题目链接 DFS的简单应用,比较繁琐的是处理输入的英文字母.用并查集也可以做(可是笔者现在还没有掌握并查集,之前只用过一次,以后学会回来补上) #include<cstdio> #incl ...

  7. sqlite3 SQL常用语句

    1. select SELECT LastName,FirstName FROM Persons; SELECT * FROM Persons; 2. where SELECT * FROM Pers ...

  8. Drag+Drop和MouseClick

    项目中的一个树形结节,既要响应拖拽事件.又要响应点击事件.实现的时候没多想,依次实现了tree_MouseClick.tree_MouseDown.tree_MouseMove事件.出现的Bug是,偶 ...

  9. Python 条件判断 循环

    age = 20 if age >= 18: print('your age is', age) print('adult') 根据Python的缩进规则,如果if语句判断是True,就把缩进的 ...

  10. 交互式的Flash图表和仪表控件AnyChart

    AnyChart使你可以创建出绚丽的交互式的Flash图表和仪表控件.是一款灵活的基于Adobe Flash和跨浏览器和跨平台的图表解决方案,被很多知名大公司所使用,可以用于仪表盘的创建.报表.数据分 ...