关于fork:多进程fork的陷阱

零、释义milvus:向量数据库langchain:python提醒工程框架一、背景本篇文章基于一个BUG的排查和解决过程,试图还原在某些场景下多过程编程的【陷阱】,达到前事不忘;后事之师的成果。程序基于python,但论断和情理实用于所有语言二、BUG问题体现最近的一段提醒工程相干的python代码,在不同操作系统的状况下,体现不一样 在macos零碎与linux零碎的单过程、macos零碎的多过程状况下均能够失常运行:在linux的多过程状况下会卡在与milvus交互的中央,如下图 三、假如milvus服务端导致(磁盘满了、内存满了、服务忙碌等)网络异样导致操作系统导致连贯milvus所用的底层调用包导致四、假如验证和BUG排查思路❌【milvus服务端导致】 独自测试了milvus的读写,服务自身没有问题,milvus所在服务器也是衰弱状态,不存在资源不足的状况。排除1❌【网络异样导致】 telnet端口通,ping通且稳固,网络是OK的。排除2✅【操作系统导致】✅【连贯milvus所用的底层调用包导致】 初步判断为多过程导致的问题,那么为何macos中的多过程失常,linux零碎的多过程就有问题呢?排查思维链(Chain-of-Thought) 于是翻阅python对于多过程模块的官网文档,直到看到了这样一段话 python多过程在不同操作系统,默认启动子过程的形式是不一样的,在windows和macos上,默认应用【spawn】,而在linux上,默认是用【fork】,那么问题很有可能出在这两种不同的启动形式上。本着控制变量法的debug形式,我在linux上将子过程的启动形式指定为了【spawn】,✅问题解决,程序胜利运行至此,尽管外表上问题解决了, 但我对解决此BUG的播种只有:【spawn】大法好,对其余稍深层次的细节无所不知,遗留有一些关键问题: spawn是什么fork是什么为什么针对此BUG,spawn能够,fork不行如果咱们偏要用fork来做,行不行,怎么做?于是,又回过头认真看了官网文档介绍以及 python官网issue讨论区,(如下图) spawn与fork概念如下 spawn:从头构建一个子过程,父过程的数据等拷贝到子过程空间内,领有本人的Python解释器,所以须要从新加载一遍父过程的包,因而启动较慢,因为数据都是本人的,安全性较高fork:除了必要的启动资源外,其余变量,包,数据等都继承自父过程,并且是copy-on-write的,也就是共享了父过程的一些内存页,因而启动较快,然而因为大部分都用的父过程数据,所以是不平安的过程fork有可能导致不平安的过程,是因为fork用到copy-on-write技术,会继承父过程的数据和堆栈,由此导致一些不平安的问题。那么针对此BUG,具体是哪个中央导致了不平安呢? 既然是milvus连贯出了错,那先从连贯下手,排查发现,首先,主过程所在文件在import模块的时候,其中一个模块(文件)发动了一次milvus的连贯,如下图 而后,主过程开始启动子过程(fork),子过程调用langchain的milvus模块,langchain中milvus连贯初始化的代码是这样写的 子过程在上图中的步骤2的时候卡住,经排查是因为子过程基本没有连上milvus,然而步骤1明明曾经判断过,如果没有连贯,则创立。再进一步看看connections.has_connection("default")这个函数,如下图 函数会判断self._connected_alias变量中是否有记录,进一步看看这个变量怎么来的 在连贯milvus时,程序保护一个self._connected_alias变量来记录是否存在连贯,connections.has_connection("default")函数只是去self._connected_alias中查看是否有连贯记录,至此发现问题关键所在,父过程在第一次连贯milvus的时候,程序在self._connected_alias变量中记录了连贯信息,当fork子过程的时候,self._connected_alias变量被一并继承给了子过程,而当子过程应用connections.has_connection("default")函数判断与milvus的连贯状态的时候,发现了从父过程继承过去的self._connected_alias变量的已连贯信息,于是判断为已有连贯,导致子过程在理论没有连贯milvus的状况下间接加载milvus的数据,引发谬误。五、解决方案解决方案1计划 采纳spawn形式启动子过程长处 简略粗犷,子过程和父过程独立,数据隔离,过程平安拓展和保护绝对不便,不必放心相似的BUG有余 spawn形式,会老老实实地copy父过程的数据(即便不须要),比拟占内存空间,启动会慢一些解决方案2计划 采纳fork形式启动子过程,须要对代码做如下批改 如果能够删除主过程中连贯milvus的代码 将milvus连贯工作都放到子过程中做如果不能删除主过程中连贯milvus的代码 在子过程判断与milvus是否已连贯的时候,不采纳connections.has_connection("default")函数,而是查看本过程本身的套接字连贯,防止来自父过程继承脏数据的净化,须要新增have_socket函数,做法如下def have_socket(): have_socket = False process_netstat = psutil.Process(os.getpid()) for _socket in process_netstat.connections(): if _socket.raddr.port == MILVUS_PORT: have_socket = True return have_socketif not have_socket(): connections.connect(**connection_args)长处 采纳fork,子过程启动快,通过优化代码逻辑,防止过程不平安的状况有余 后续的代码拓展和保护都要留神代码逻辑,防止相似BUG六、总结写多线程/多过程代码的时候,须要留神具体代码逻辑,防止继承的脏数据导致线程/过程不平安对于资源束缚不大,性能要求不高的场景,多过程一律用spawn七、号外【python开发组音讯】将spawn在所有平台上设置为默认选项曾经提上日程 ,打算3.14版本正式上线 https://discuss.python.org/t/switching-default-multiprocessin...【fork的长处和利用场景】fork也不是一无是处,对于只读数据须要共享的状况,还是十分省内存资源, 比方编写模型预测的并发服务,fork只加载1份模型到内存,而spawn会加载N份,gunicorn的-preload参数就是基于fork的copy-on-write技术,达到模型只加载一次的目标In general, fork is bad, but it's also convenient and people rely on it to prepare data in a main process and then "duplicate" the process to inherit cooked data. -Victor Stinner版本信息python3.11.4langchain==0.0.146ReferencesPython crashes on macOS after fork with no execmultiprocessing's default posix start method of 'fork' is broken: change to 'spawn’Multiprocessing causes Python to crash and gives an error may have been in progress in another thread when fork() was called机器学习模型API多过程内存共享写时复制https://docs.python.org/3/library/multiprocessing.htmlhttps://discuss.python.org/t/switching-default-multiprocessin...

September 10, 2023 · 1 min · jiezi

关于fork:微软修改-MIT-项目原作者版权声明引争议自动化脚本出问题-现已恢复正确-LICENSE-文件版权信息

近日,微软在 fork 一个 MIT 开源我的项目的时候,保留了原我的项目的 MIT 许可协定,但将原作者的著作权申明批改为了微软本人,由此引发了不小的争议。 据悉,此次我的项目是由开发者 Leśny Rumcajs 基于 MIT 许可协定所开发 —— grpc_bench。微软在 fork 该我的项目后,将原来的“2020 LesnyRumcajs”版权申明改为“Microsoft Corporation.”,从而受到业内开发者们的质疑。 对于此次事件,微软开源我的项目办公室负责人 Jeff Wilcox 在 12 月 16 日发文解释称:这全都是“自动化脚本惹的祸”——该谬误是由一个在新存储库中提交模板文件的(Bot)机器人引起的。 Jeff Wilcox 在发文中回复称:“产生这种事我很道歉。”“咱们已合并了复原正确 LICENSE 文件和版权信息的申请,并与上游作者 Leśny Rumcajs 取得联系,他明天早上给咱们发了电子邮件。咱们还将思考复原咱们的 bot 所做的全副承诺(Bot 用一个样板入门指南更新了自述文件)。” Jeff Wilcox 示意,该问题是由机器人造成的,该机器人设计用于提交新存储库中的模板文件。而他写这段代码是为了避免微软以往公布我的项目时遇到的其余问题——不应该在 forks 上运行。 Jeff Wilcox 指出了此次事件的问题所在,尽可能实现凋谢: 新存储库上利用的模板位于:https://github.com/microsoft/...谬误仿佛呈现在新存储库工作流的这一行:https://github.com/microsoft/...现有的零碎甚至试图用该日志信息来领导工程师:(https://github.com/microsoft/...):“this.log.push({message:Repository${subMessage},模板文件将不会提交。请查看许可证和其余文件以理解现有的任务。})”......Jeff Wilcox 还补充称,他们有很多对于 forks 的流程,并且必须施行管制,以确保人们理解该指南。 后续,Jeff Wilcox 也将和团队将分心审核所有的 forks 存储库,并将相似的更改复原到其余我的项目中。 早在几年前,Jeff Wilcox 的团队就已开始“锁定”forks 以强制执行其流程。Jeff Wilcox 和团队心愿开发者们将我的项目转移到各自的 GitHub 帐户中,以激励他们参加上游我的项目。 只管微软方面已着手解决该问题,但仍旧引发了不少网友的调侃: 对于 MIT 协定:MIT 协定是一项常见的开源我的项目许可协定,被授权人有权力应用、复制、批改、合并、出版发行、分布、再受权及贩售软件及软件的正本,但必须蕴含版权申明和许可申明。 ...

December 27, 2021 · 1 min · jiezi