Python中使用fork()与exec()遇到的异常问题求助
Python fork/exec 问题解析
首先看你编写的测试代码:
import sys import os print("Start: " + str(os.getpid())) sys.stdout.flush() if len(sys.argv) > 1: pid = os.fork() if pid == 0: os.execvp(sys.argv[1], sys.argv[1:]) elif pid > 0: print("Fork: " + str(pid)) sys.stdout.flush() x = os.wait() if x[0] != pid: # NEEDED os.waitpid(pid,0) # NEEDED print("End: " + str(x[0])) else: print("Fork failed", file=sys.stderr) sys.exit(1) else: print("End") sys.stdout.flush()
你使用以下命令运行:
python test.py python test.py ps
得到的输出:
Start: 999773 Fork: 999777 Start: 999777 Fork: 999781 PID TTY TIME CMD 999773 ? 00:00:00 python3 999777 ? 00:00:00 python3 999781 ? 00:00:00 ps End: 999781 End: 999774
移除标注NEEDED的两行代码后,得到错误输出:
Start: 1000822 Fork: 1000830 End: 1000824 Python path configuration: PYTHONHOME = (not set) PYTHONPATH = (not set) program name = '/usr/bin/python3' isolated = 0 environment = 1 user site = 1 import site = 1 sys._base_executable = '/usr/bin/python3' sys.base_prefix = '/usr' sys.base_exec_prefix = '/usr' sys.executable = '/usr/bin/python3' sys.prefix = '/usr' sys.exec_prefix = '/usr' sys.path = [ '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', ] Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding Python runtime state: core initialized ModuleNotFoundError: No module named 'encodings' Current thread 0x00007f27b84f7740 (most recent call first): <no Python frame>
下面针对两个问题逐一解析:
一、神秘进程999774的来源
999774是一个僵尸进程,它的出现是因为你的主进程(999773)意外捕获到了一个不属于它的子进程,具体原因可能是:
- 孤儿进程被错误收养:Unix系统中,当某个进程的父进程提前退出,它会变成孤儿进程被init接管。如果系统中存在未被处理的僵尸进程,有可能出现系统将其分配给你的前台进程(999773)收养的情况,导致
os.wait()捕获到它。 - shell临时进程残留:你运行命令时,shell可能创建了临时辅助进程来处理命令行参数,该进程完成任务后退出成为僵尸,恰好被你的主进程捕获。
从ps输出可以看到,999774并没有出现在活跃进程列表中,说明它已经退出并成为僵尸。你代码中那两行NEEDED的代码就是为了避免这种情况:当os.wait()捕获到无关进程时,通过os.waitpid()确保最终等待自己创建的子进程(999777)。
二、移除等待代码后的Python初始化错误
移除那两行代码后,主进程调用os.wait()等待任意子进程退出,如果先捕获到无关僵尸进程(比如1000824)就直接退出,此时真正的子进程(1000830)会变成孤儿进程被init接管,进而引发初始化错误:
- 环境变量被重置:init接管孤儿进程后会重置其运行环境,部分与本地化相关的环境变量丢失,导致Python无法获取文件系统编码(
init_fs_encoding失败)。 - 核心模块加载失败:Python初始化时必须加载
encodings模块处理字符编码,环境变量丢失会导致Python无法找到该模块,触发ModuleNotFoundError。 - 终端连接断开:主进程退出后,子进程与终端的连接被切断,Python依赖终端的配置无法读取,进一步导致初始化失败。
本质上是主进程提前退出导致子进程的运行环境被破坏,最终让Python无法完成初始化。
内容的提问来源于stack exchange,提问作者user1636349
相关产品推荐
相关产品推荐

