当子进程发送信号时,父进程在随后的read()上收到KeyboardInterrupt

时间:2019-06-14 02:06:29

标签: python python-3.x python-multiprocessing

在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信号通知该命令子进程结束包装并退出。

此命令子流程完成后,将进行一些后处理。这可以通过使用Pool子项中的subprocess.run来实现,例如:

            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,以确保在子初始化期间在Pool子进程中将其忽略;但是,这没有帮助。我也尝试了有无start_new_session = True。我也尝试将SIGINT设置为在Pool子级中处理,但是在发生这种情况时不会调用处理程序。如果我故意向Pool子级发送SIGINT,则会调用处理程序。

如果在尝试创建下一个进程之前仅time.sleep(10)进行该进程,它将休眠整个时间,然后立即认为KeyboardInterrupt在subprocess.run内部进行第一次读取时就到达了。 / p>

出现的行为 使得向Pool子项的命令子进程传递信号导致Python认为已将KeyboardInterrupt发送给Pool子项,并且该KeyboardInterrupt在第一个IO上处理尝试。

我的问题是:为什么会发生这种情况(即,我错过了什么?),如何防止这种情况发生?

我还注意到,当Popened命令终止时,我在命令子进程上下文中捕获并记录了KeyboardInterrupt。这可能是解释器“记住”存在悬而未决的KeyboardInterrupt的情况,该中断最终在以后处理?如果是这样,我应该如何抑制它或“清除” KeyboardInterrupt?

编辑:随着我继续对此进行研究,我发现如果我注释掉所有的select / readline / log循环,则一切正常。因此,这似乎是从命令子进程中读取某些内容,从而杀死了Pool子级。

0 个答案:

没有答案