You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 09:20:15