ARM macOS下Python3 os.fork()导致父进程重复执行问题
问题场景
尝试通过os.fork()实现多进程,同时启动Flask服务器和向其发送请求的客户端,代码如下:
def main(): """ Start a local server and call it using parallel processes. """ pid = os.fork() if pid == 0: # GET data get() return 0 else: # Run the server run() return 0 if __name__ == "__main__": main()
执行命令:
python main.py <SOME_ARGS>
得到输出:
* Serving Flask app 'server.server' < ---- 服务器启动 * Debug mode: on Traceback (most recent call last): < ---- 客户端运行,报错回溯 . . . requests.exceptions.ConnectionError: HTTPConnectionPool(host='127.0.0.1', port=3000): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x100919640>: Failed to establish a new connection: [Errno 61] Connection refused')) * Running on http://127.0.0.1:3000. < ---- 服务器启动完成 Hello, World! < ---- 客户端再次运行,成功
核心问题:预期父进程仅执行一次,但实际出现两次执行的情况。
问题原因
Flask开启Debug模式时,默认启用自动重载器(reloader),该机制会重新加载主模块并fork新进程运行应用。这导致main()函数被执行两次:第一次是初始启动进程,第二次是reloader触发的重载进程,进而引发两次fork操作和两次客户端请求。此外,第一次客户端请求时,Flask服务尚未完成初始化,因此出现连接拒绝错误;第二次请求时服务已就绪,所以请求成功。
解决方案
以下是几种可行的解决方法:
- 关闭Debug模式:在Flask的
run()方法中设置debug=False,彻底禁用reloader机制。 - 保留Debug但关闭reloader:若需要Debug日志但无需自动重载,设置
run(debug=True, use_reloader=False)。 - 分离服务启动逻辑:将Flask服务的定义与启动代码放到单独模块中,避免reloader重新执行包含fork逻辑的
main()函数。 - 添加启动等待(可选):在客户端进程中添加短暂延迟,确保服务有足够时间完成启动,避免首次连接失败。
修改后的示例代码(保留Debug并关闭reloader):
from flask import Flask import os import requests import time app = Flask(__name__) @app.route('/') def hello(): return "Hello, World!" def run(): # 关闭reloader,避免重复执行main逻辑 app.run(port=3000, debug=True, use_reloader=False) def get(): # 等待1秒,确保服务启动完成 time.sleep(1) try: response = requests.get('http://127.0.0.1:3000') print(f" {response.text}") except Exception as e: print(f"Error: {e}") def main(): pid = os.fork() if pid == 0: get() return 0 else: run() return 0 if __name__ == "__main__": main()
内容的提问来源于stack exchange,提问作者Mahdi Habibi
相关产品推荐
相关产品推荐

