我正在使用Python使用子进程模块调用C ++程序。由于程序需要一些时间来运行,我希望能够使用Ctrl + C终止它。我在StackOverflow上看到了一些关于这方面的问题,但没有一个解决方案对我有用。
我想要的是在KeyboardInterrupt上终止子进程。这是我的代码(类似于其他问题中的建议):
import subprocess
binary_path = '/path/to/binary'
args = 'arguments' # arbitrary
call_str = '{} {}'.format(binary_path, args)
proc = subprocess.Popen(call_str)
try:
proc.wait()
except KeyboardInterrupt:
proc.terminate()
但是,如果我运行它,代码将挂起,等待进程结束,并且永远不会注册KeyboardInterrupt。我也尝试了以下内容:
import subprocess
import time
binary_path = '/path/to/binary'
args = 'arguments' # arbitrary
call_str = '{} {}'.format(binary_path, args)
proc = subprocess.Popen(call_str)
time.sleep(5)
proc.terminate()
此代码段在终止程序时工作正常,因此不是发送终止的实际信号就是问题。
如何更改代码以便可以在KeyboardInterrupt上终止子进程?
我正在运行Python 2.7和Windows 7 64位。提前谢谢!
我尝试过的一些相关问题:
答案 0 :(得分:3)
我找到了一种方法来做到这一点,类似于Jean-Francois对循环的回答,但没有多线程。关键是使用Popen.poll()来确定子进程是否已完成(如果仍在运行则返回None)。
import subprocess
import time
binary_path = '/path/to/binary'
args = 'arguments' # arbitrary
call_str = '{} {}'.format(binary_path, args)
proc = subprocess.Popen(call_str)
try:
while proc.poll() is None:
time.sleep(0.1)
except KeyboardInterrupt:
proc.terminate()
raise
我在KeyboardInterrupt之后添加了一个额外的加注,因此除了子进程之外,Python程序也被中断了。
编辑:根据eryksun的评论更改传递给time.sleep(0.1)以减少CPU消耗。
答案 1 :(得分:2)
我在Windows上的丑陋但成功的尝试:
import subprocess
import threading
import time
binary_path = 'notepad'
args = 'foo.txt' # arbitrary
proc = None
done = False
def s():
call_str = '{} {}'.format(binary_path, args)
global done
global proc
proc = subprocess.Popen(call_str,stdout=subprocess.PIPE)
proc.wait()
done = True
t = threading.Thread(target=s)
t.start()
try:
while not done:
time.sleep(0.1)
except KeyboardInterrupt:
print("terminated")
proc.terminate()
创建子进程运行的线程。导出proc
变量。
然后在非活动循环中永远等待。按下CTRL + C时,将触发异常。进程间通信(例如:proc.wait()
)与CTRL + C处理冲突。在线程中运行时,没有这样的问题。
注意:我曾尝试使用threading.lock()
来避免此时间循环,但偶然发现了同一个CTRL + C忽略。