Python2subprocess不会将Ctrl-C信号传递到具有交错标准输出stderr的docker容器

我有一个python 2subprocess,启动docker容器,并尝试交错stdout和stderr:

from subprocess import check_output, Popen, PIPE, STDOUT from threading import Thread command_args = [ "docker", "run", "-i", "--rm", '--entrypoint', 'sleep', # Pretend long running task 'ubuntu:trusty', '20' ] print('Running subprocess') p = Popen(command_args, stdin=PIPE, stdout=PIPE, stderr=PIPE) def log_pipe(pipe): for line in iter(pipe.readline, b''): print(line.rstrip()) stdout_thread = Thread(target=log_pipe, args=[p.stdout]) stderr_thread = Thread(target=log_pipe, args=[p.stderr]) stdout_thread.start() stderr_thread.start() stdout_thread.join() stderr_thread.join() p.communicate() if p.returncode != 0: print('Error') 

当我从一个bashterminal发起这个时,有时候我想在它结束之前杀掉长时间运行的任务。 但是当我按Ctrl-C时,信号似乎没有到达容器。 它似乎要等到长时间运行的任务完成,然后调低python进程。

我可以通过不使用线程来获得我想要的Ctrl-C行为:

 from subprocess import check_output, Popen, PIPE, STDOUT from threading import Thread command_args = [ "docker", "run", "-i", "--rm", '--entrypoint', 'sleep', # Pretend long running task 'ubuntu:trusty', '20' ] print('Running subprocess') p = Popen(command_args, stdin=PIPE, stdout=PIPE, stderr=PIPE) def log_pipe(pipe): for line in iter(pipe.readline, b''): print(line.rstrip()) log_pipe(p.stdout) log_pipe(p.stderr) if p.returncode != 0: print('Error') 

Ctrl-C会立即终止。 但是,没有更好的stdout和stderr的交错。


那么是否有一种方法可以同时实现交叉和能够立即杀死长时间运行的应用?

也可以解释一下导致这种行为的pythonsubprocess和线程下面是怎么回事?


一些澄清:

这只是一个运行sleep 20代表一些长期运行任务的玩具例子。 我真正的应用程序运行了很长时间,并具有stdout和stderr我想分开处理,不同的修改,并打印交错。 log_pipe方法只是一个简单的例子,它保持简短 – 我们对两个stream使用不同的逻辑,所以它们不能仅仅使用Popen(..., stderr=STDOUT)合并在一起。

我只在示例中使用了--entrypoint来明确清楚地说明哪些可执行文件和参数正在运行 – 我们通常不这样做。

使用python 2.7.12和docker 17.03.1-ce,编译c6d412e。


谢谢!