如何使用python的多处理池处理KeyboardInterrupt事件?这是一个简单的例子:
from multiprocessing import Pool
from time import sleep
from sys import exit
def slowly_square(i):
sleep(1)
return i*i
def go():
pool = Pool(8)
try:
results = pool.map(slowly_square, range(40))
except KeyboardInterrupt:
# **** THIS PART NEVER EXECUTES. ****
pool.terminate()
print "You cancelled the program!"
sys.exit(1)
print "\nFinally, here are the results: ", results
if __name__ == "__main__":
go()
Run Code Online (Sandbox Code Playgroud)
当运行上面的代码时,KeyboardInterrupt当我按下时会引发上升^C,但是该过程只是挂起,我必须在外部杀死它.
我希望能够随时按下^C并使所有进程正常退出.
Python中是否有某种方法可以捕获KeyboardInterrupt事件而不将所有代码放在try- except语句中?
如果用户按Ctrl+,我想干净利落地退出C.
我正在用Python编写命令行实用程序,因为它是生产代码,所以应该能够干净地关闭而不会将大量的东西(错误代码,堆栈跟踪等)转储到屏幕上.这意味着我需要捕获键盘中断.
我尝试过使用try catch块,如:
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print 'Interrupted'
sys.exit(0)
Run Code Online (Sandbox Code Playgroud)
并捕捉信号本身(如在这篇文章中):
import signal
import sys
def sigint_handler(signal, frame):
print 'Interrupted'
sys.exit(0)
signal.signal(signal.SIGINT, sigint_handler)
Run Code Online (Sandbox Code Playgroud)
这两种方法在正常操作期间似乎都能很好地工作.但是,如果在应用程序结束时清理代码期间出现中断,Python似乎总是在屏幕上打印一些东西.捕获中断给出了
^CInterrupted
Exception KeyboardInterrupt in <bound method MyClass.__del__ of <path.to.MyClass object at 0x802852b90>> ignored
Run Code Online (Sandbox Code Playgroud)
而处理信号也给出了
^CInterrupted
Exception SystemExit: 0 in <Finalize object, dead> ignored
Run Code Online (Sandbox Code Playgroud)
要么
^CInterrupted
Exception SystemExit: 0 in <bound method MyClass.__del__ of <path.to.MyClass object at 0x802854a90>> ignored
Run Code Online (Sandbox Code Playgroud)
这些错误不仅难看,而且对于没有源代码的最终用户来说也不是很有帮助!
此应用程序的清理代码相当大,因此真正的用户可能会遇到此问题.有没有办法捕获或阻止此输出,或者它只是我必须处理的东西?
我正在运行这个简单的代码:
import threading, time
class reqthread(threading.Thread):
def run(self):
for i in range(0, 10):
time.sleep(1)
print('.')
try:
thread = reqthread()
thread.start()
except (KeyboardInterrupt, SystemExit):
print('\n! Received keyboard interrupt, quitting threads.\n')
Run Code Online (Sandbox Code Playgroud)
但是当我运行它时,它会打印出来
$ python prova.py
.
.
^C.
.
.
.
.
.
.
.
Exception KeyboardInterrupt in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored
Run Code Online (Sandbox Code Playgroud)
实际上python线程忽略我的Ctrl+ C键盘中断而不打印Received Keyboard Interrupt.为什么?这段代码有什么问题?
我目前正在为shell中运行的专用服务器开发包装器.包装器通过子进程生成服务器进程,并观察并响应其输出.
必须明确地为专用服务器提供一个命令才能正常关闭.因此,CTRL-C不得访问服务器进程.
如果我捕获KeyboardInterrupt异常或覆盖python中的SIGINT处理程序,服务器进程仍然会收到CTRL-C并立即停止.
所以我的问题是:如何防止子进程接收CTRL-C/Control-C/SIGINT?
我正在Windows上编写python 2.6.6代码,如下所示:
try:
dostuff()
except KeyboardInterrupt:
print "Interrupted!"
except:
print "Some other exception?"
finally:
print "cleaning up...."
print "done."
Run Code Online (Sandbox Code Playgroud)
dostuff()是一个永远循环的函数,一次从输入流读取一行并对其进行操作.我希望能够在我按下ctrl-c时停止并清理它.
发生的事情是,下面的代码except KeyboardInterrupt:根本没有运行.打印的唯一内容是"清理......",然后打印出如下所示的回溯:
Traceback (most recent call last):
File "filename.py", line 119, in <module>
print 'cleaning up...'
KeyboardInterrupt
Run Code Online (Sandbox Code Playgroud)
因此,异常处理代码没有运行,并且traceback声称在finally子句期间发生了KeyboardInterrupt ,这没有意义,因为命中ctrl-c是导致该部分首先运行的原因!甚至通用except:子句也没有运行.
编辑:基于注释,我try:用sys.stdin.read()替换了块的内容.问题仍然与描述完全一致,finally:块的第一行运行,然后打印相同的回溯.
编辑#2: 如果我在阅读后添加了很多东西,那么处理程序就可以了.所以,这失败了:
try:
sys.stdin.read()
except KeyboardInterrupt:
...
Run Code Online (Sandbox Code Playgroud)
但这有效:
try:
sys.stdin.read()
print "Done reading."
except KeyboardInterrupt:
...
Run Code Online (Sandbox Code Playgroud)
这是打印的内容:
Done reading. Interrupted!
cleaning up...
done.
Run Code Online (Sandbox Code Playgroud)
因此,出于某种原因,"完成阅读".即使前一行发生异常,也会打印行.这不是一个真正的问题 - 显然我必须能够在"try"块内的任何地方处理异常.但是,打印不能正常工作 - 它不会像之前那样打印换行符!"Interruped"印在同一条线上......前面有一个空格,出于某种原因......?无论如何,在那之后代码完成它应该做的事情. …
我在Win7 64位上运行64位Python 2.7.3.我可以通过这样做可靠地崩溃Python解释器:
>>> from scipy import stats
>>> import time
>>> time.sleep(3)
Run Code Online (Sandbox Code Playgroud)
并在睡眠期间按下Control-C.未引发KeyboardInterrupt; 翻译崩溃了.打印如下:
forrtl: error (200): program aborting due to control-C event
Image PC Routine Line Source
libifcoremd.dll 00000000045031F8 Unknown Unknown Unknown
libifcoremd.dll 00000000044FC789 Unknown Unknown Unknown
libifcoremd.dll 00000000044E8583 Unknown Unknown Unknown
libifcoremd.dll 000000000445725D Unknown Unknown Unknown
libifcoremd.dll 00000000044672A6 Unknown Unknown Unknown
kernel32.dll 0000000077B74AF3 Unknown Unknown Unknown
kernel32.dll 0000000077B3F56D Unknown Unknown Unknown
ntdll.dll 0000000077C73281 Unknown Unknown Unknown
Run Code Online (Sandbox Code Playgroud)
这使得无法中断长时间运行的scipy计算.
谷歌搜索"forrtl"等,我看到这种问题的建议是由于使用了一个覆盖Ctrl-C处理的Fortran库.我没有看到Scipy跟踪器上的错误但是假设Scipy是一个用于Python的库,我会认为这是一个错误.它打破了Python对Ctrl-C的处理.这有什么解决方法吗?
编辑:关注@ cgohlke的建议我尝试在导入scipy后添加自己的处理程序. 关于相关问题的这个问题表明添加信号处理程序不起作用.我尝试通过pywin32 使用Windows API SetConsoleCtrlHandler函数: …
我一直在调试一个Python程序,它在收到KeyboardInterrupt异常后会出现段错误.这通常是通过Ctrl+C从外壳按下来完成的.为了测试特定代码更改是否修复了错误,我有一个小的shell脚本,SIGINT在启动后随机时间发送到程序.我Ctrl+C遇到的问题是发送似乎对程序的影响不同于发送信号SIGINT,因此不会导致错误出现,所以我很想知道这两个动作之间的区别是什么.
该程序根本不捕获任何键盘操作,并且只是一个包含一些线程/进程的python程序.它不安装任何信号处理程序(虽然Python确实如此),并stty -a给出intr = ^C.我怀疑它可能是Ctrl+C发送SIGINT到所有子进程/线程而kill -INT只发送到主进程,但这是我的怀疑.
这是发送的shell脚本kill -INT.
wait
while :; do
seconds="$(python -c 'import random; print random.random()*4')"
./mandos --debug --configdir=confdir \
--statedir=statedir --no-restore --no-dbus &
pid=$!
{ sleep $seconds; kill -INT $pid; } &
fg %./mandos
status=$?
if [ $status -gt 1 ]; then
echo "Failed exit $status after $seconds seconds"
break
fi
wait
done
Run Code Online (Sandbox Code Playgroud) 我有一个非常小的测试程序,除了执行asyncio事件循环之外什么都不做:
import asyncio
asyncio.get_event_loop().run_forever()
Run Code Online (Sandbox Code Playgroud)
当我在Linux上运行此程序并按Ctrl+时C,程序将正常终止,但有KeyboardInterrupt异常.在Windows上按Ctrl+ C什么也没做(用Python 3.4.2测试).即使在Windows上,一个简单的无限循环也能正确time.sleep()引发KeyboardInterrupt:
import time
while True:
time.sleep(3600)
Run Code Online (Sandbox Code Playgroud)
为什么asyncio的事件循环会抑制Windows上的KeyboardInterrupt?
我在某处读到KeyboardInterrupt异常只在Python的主线程中引发.我还读到在子线程执行时主线程被阻塞.那么,这是否意味着CTRL+ C永远不会到达子线程.我尝试了以下代码:
def main():
try:
thread = threading.Thread(target=f)
thread.start() # thread is totally blocking (e.g., while True)
thread.join()
except KeyboardInterrupt:
print "Ctrl+C pressed..."
sys.exit(1)
def f():
while True:
pass # do the actual work
Run Code Online (Sandbox Code Playgroud)
在这种情况下,CTRL+ C对执行没有影响.它就像是无法收听信号.我理解这是错误的方式吗?有没有其他方法可以使用CTRL+ 杀死线程C?