背景
因为最近公司的某个项目需要对接依图科技的实时语音转写服务,但由于对方只提供了Java与Python的接口(其实依图科技的实时语音转写接口采用的是grpc,虽然我给领导提过可以让对方用proto文件快速生成其他语言的接口,但无赖领导没有采纳),而我们的产品是基于C/C++的,所以决定用Python写一个中转服务(如果开始知道Python这么多坑,我一定选Java)。
问题
由于GIL的存在,Python服务器就只能采用accept-fork模式,但服务运行一段时间后,抛出异常信息——文件描述符溢出——,确定fork前除了监听套接字与连接套接字外,没有创建其他文件描述符,而且fork之后在父进程关闭了连接套接字,在子进程关闭了监听套接字,理论上不应该存在文件描述符泄露。
解决方案
最后使用lsof命令查看父进程的相关记录,发现有未关闭的PIPE。后面查看multiprocessing的代码,发现start方法会默认创建一个PIPE用于与子进程通信,该pipe的描述符保存在sentinel字段,官网关于sentinel的描述
A numeric handle of a system object which will become “ready”
when the process ends.
You can use this value if you want to wait on several events at once using multiprocessing.connection.wait(). Otherwise calling join() is simpler.
O