多进程中对等待态进程运行pexpect报错如何处理?QNX Python2.7环境
问题1 原因解释
这个报错本质是Unix(包括QNX)系统waitpid系统调用的权限限制,结合Python 2.7 multiprocessing的默认fork启动逻辑共同导致的:
- 你在主进程中调用
pexpect.spawn启动testPexpectError.py时,这个被启动的子进程的父进程ID就是你的主进程ID,只有父进程有权限调用waitpid获取该子进程的状态。 - Python 2.7的
multiprocessing.Process在Unix平台默认使用fork机制创建新进程,fork出来的工作进程会完整复制主进程的内存空间,包括你提前创建的pexp对象(里面存储了testPexpectError.py的PID),但这个工作进程并不是testPexpectError.py的父进程。 - 当你在工作进程中调用
pexpect的expect、close方法时,方法内部会调用isalive(),isalive()会尝试用waitpid获取子进程状态,由于工作进程没有对应权限,系统调用返回ECHILD(不存在对应子进程)错误,pexpect就会抛出你看到的异常。 - 主线程运行时所有逻辑都在主进程中,主进程是子进程的合法父进程,调用
waitpid不会报错,所以不会触发异常。
问题2 规避方案
你可以根据自己的业务场景选以下任意一种方案:
- 最推荐的方案:把
pexpect.spawn的创建逻辑移到工作进程内部。这样启动的testPexpectError.py的父进程就是工作进程,有权限调用waitpid,不会触发异常。修改后的pexpectTest.py参考代码:
import multiprocessing import pexpect import sys def test(): pexp = pexpect.spawn('python testPexpectError.py') pexp.delaybeforesend = False pexp.logfile = sys.stdout pexp.sendline('line') pexp.expect('>', timeout=None) pexp.close() mp = multiprocessing.Process(target=test) mp.start() mp.join()
- 如果你的业务逻辑必须在主进程提前创建pexpect对象,可以把
multiprocessing换成threading实现多并发:同一进程下的所有线程共享父进程权限,调用waitpid不会有问题。 - 如果必须保留现有逻辑结构,可以给pexpect打补丁修改
isalive()方法,捕获ECHILD错误,遇到该错误时直接返回False(代表子进程已终止)即可,不需要抛出异常。
内容的提问来源于stack exchange,提问作者that's not entirely true
相关产品推荐
相关产品推荐

