• 多进程和atexit清理函数


    前言:
      最近帮朋友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开发者的常规想法. 当然任何诡异的现象, 背后一定有迹可循.

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

       

  • 相关阅读:
    java中的基本数据类型以及对应的包装类
    JQuery 基础
    题库一
    String、StringBuffer和StringBuilder的区别
    ideal控制台输出乱码
    python进阶
    python基础
    请求一个网页时,web服务做了什么?[以php为例]
    go defer看到你头晕的操作
    计算机基础-数据结构-栈
  • 原文地址:https://www.cnblogs.com/mumuxinfei/p/4527680.html
Copyright © 2020-2023  润新知