多进程和atexit清理函数
前言:
最近帮朋友review其模块服务代码, 使用的是python的twisted网络框架. 鉴于之前并没有使用过, 于是决定好好研究一番.
不过这个问题, 和twisted网络框架本身没有关系, 而是为了提升QPS性能, 引入了多进程模型而遇到的一个奇怪问题.
本文将讲述python的多进程机制, 以及atexit的清理函数机制. 权作python的学习笔记.
场景构造:
具体的业务代码可以简化为如下所述:
父进程开启多个常驻子进程后, 安然"退休"并结束运行.
进程的创建借助multiprocessing模块来实现, 其使用方式如thread管理接口相仿.
编辑python代码文件 subproc_sample.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #! /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开发者的常规想法. 当然任何诡异的现象, 背后一定有迹可循.
写在最后:
如果你觉得这篇文章对你有帮助, 请小小打赏下. 其实我想试试, 看看写博客能否给自己带来一点小小的收益. 无论多少, 都是对楼主一种由衷的肯定.
posted on 2015-05-25 19:13 mumuxinfei 阅读(1260) 评论(1) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构