python - 当子进程被发送信号时,父进程在随后的 read() 上收到 KeyboardInterrupt
问题描述
在 MacOS 上使用 Python 3.7:
我有一个多处理池,其中子进程处理工作单元。
反过来,这些 Pool 子进程中的每一个都必须运行一个命令子进程,这是使用 Popen 完成的;例如:
with Popen([CMD, ARGS], stdin=PIPE, stdout=PIPE, stderr=STDOUT, encoding='utf8', close_fds=True, cwd=JSBOT_DIR, start_new_session=True, ) as process:
try:
while process.poll() is None:
(ready, _, error) = select([process_stdout], [], [process_stdout], timeout)
if process_stdout in ready:
line = process_stdout.readline()
while line:
LOGGER.info(f'{line.rstrip()}')
line = process_stdout.readline()
except KeyboardInterrupt:
LOGGER.info('Got KeyboardInterrupt from subprocess')
# ...
process.wait(10)
这个命令子进程可以通过发送一个 SIGUSR2 来通知它是时候结束和退出了。
一旦这个命令子过程完成,就会发生一些后处理。这是subprocess.run
在 Pool child 中使用实现的,例如:
result = subprocess.run(['ffmpeg', '-y', '-i', pathname, '-ac', '1', '-ar', '48000', '-c:a', 'pcm_s16le',
normalized_filename], stderr=STDOUT, stdout=PIPE)
我遇到的问题是,在执行 后subprocess.run()
,Python 立即发出一个 KeyboardInterrupt,并且Pool孩子立即死亡:
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/subprocess.py", line 474, in run
stdout, stderr = process.communicate(input, timeout=timeout)
File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/subprocess.py", line 926, in communicate
stdout = self.stdout.read()
KeyboardInterrupt
我尝试设置 SIGUSR2 和 SIGINT 以确保在子初始化期间在池子进程中被忽略;但是,这并没有帮助。我也尝试过使用和不使用 start_new_session=True。我还尝试将 SIGINT 设置为在 Pool 子项中处理,但发生这种情况时不会调用处理程序。如果我故意向 Pool 子项发送 SIGINT,则会调用处理程序。
如果我time.sleep(10)
在尝试创建下一个进程之前创建该进程,它将完全休眠,然后立即相信 KeyboardInterrupt 在第一次读取 inside 时已经到达subprocess.run
。
这种行为似乎是这样的,即向 Pool 子进程的命令子进程传递信号会导致 Python 相信 KeyboardInterrupt 已发送到 Pool 子进程,并且在第一次 IO 尝试时处理此 KeyboardInterrupt。
我的问题是:为什么会发生这种情况(即,我错过了什么?),以及如何防止这种情况发生?
我还注意到,当 Popened 命令终止时,我在命令子进程上下文中捕获并记录了一个 KeyboardInterrupt。这可能是解释器“记住”有一个待处理的 KeyboardInterrupt 最终在稍后处理的情况吗?如果是这样,我该如何抑制它或“清除”键盘中断?
编辑:当我继续玩这个时,我发现如果我注释掉所有的 select/readline/log 循环,一切正常。因此,这似乎是从命令子进程中读取某些内容的行为,这会杀死 Pool 子进程。
解决方案
推荐阅读
- jquery-selectors - 不是 mailto 链接的锚标记的角度选择器
- javascript - ./src/actions/productActions.js 尝试导入错误:“PRODUCT_LIST_FAIL”未从“../reducers/productReducers”导出
- javascript - 在 react-native-gesture-handler/Swipeable 中如何添加 post API
- python - 如何在 python 中使用验证数据训练 knn 模型
- python - Python 预算自动化 - 使用不同的工作表创建多个工作簿 - XLSXwriter
- javascript - 如何在 prisma 中使用 findUnique 和 post id 和 prodCode 来查找帖子
- gitlab-ci - 如何运行**要么**主要 CI 作业**或**包含的配置?
- android - 从 API 格式化数据
- node.js - Google Cloud Functions 向 Firestore 中的地图添加值
- node.js - 如何导出描述/测试并在另一个测试文件中重复使用它们