在阅读之前请不要认为它是重复的,有很多关于multithreading
和keyboard interrupt
的问题,但是我没有找到任何考虑的os.system,看起来它很重要。
我有一个python脚本,它在工作线程中进行一些外部调用。
如果我按ctrl+c
,我希望它退出,但它看起来像是主线程忽略了它。
像这样的:
from threading import Thread
import sys
import os
def run(i):
while True:
os.system("sleep 10")
print i
def main():
threads=[]
try:
for i in range(0, 3):
threads.append(Thread(target=run, args=(i,)))
threads[i].daemon=True
threads[i].start()
for i in range(0, 3):
while True:
threads[i].join(10)
if not threads[i].isAlive():
break
except(KeyboardInterrupt, SystemExit):
sys.exit("Interrupted by ctrl+c\n")
if __name__ == '__main__':
main()
令人惊讶的是,如果我将os.system("sleep 10")
更改为time.sleep(10)
,它就可以正常工作。
我不知道你用的是什么操作系统和shell。我用zsh描述Mac OS X和Linux(bash/sh的行为应该类似)。
当您按下Ctrl+C时,当前终端receive the signal SIGINT中前台运行的所有程序。在您的例子中,它是您的主python进程和os.system生成的所有进程。
由os.system生成的进程然后终止其执行。通常当python脚本接收到SIGINT时,它会引发KeyboardInterrupt异常,但是主进程会忽略SIGINT,因为
os.system()
。Pythonos.system()
calls the Standard C functionsystem()
,这使得调用进程忽略SIGINT(man Linux/man Mac OS X)。因此,您的python线程都不接收SIGINT,只有子进程才能获得它。
当删除os.system()调用时,python进程停止忽略SIGINT,您将得到
KeyboardInterrupt
。您可以用
subprocess.call(["sleep", "10"])
替换os.system("sleep 10")
。subprocess.call()
不会使进程忽略SIGINT。当我第一次学习python多线程时,我遇到同样的问题的次数已经超过了我可以倒数的次数。
在循环中添加sleep调用将使您的主线程阻塞,这将允许它仍然听到并接受异常。您要做的是利用
Event
类在子线程中设置一个事件,该事件将用作中断执行的退出标志。您可以在KeyboardInterrupt
异常中设置此标志,只需将该异常的except子句放在主线程中。我不完全确定python特定的sleep和被称为one的os之间的不同行为是怎么回事,但是我提供的补救方法应该能达到您所期望的最终结果。只是猜测一下,名为one的操作系统可能会以不同的方式阻塞解释器本身?
请记住,通常在需要线程的大多数情况下,主线程将继续执行某些操作,在这种情况下,您的简单示例中的“休眠”将被隐含。
http://docs.python.org/2/library/threading.html#event-objects
相关问题 更多 >
编程相关推荐