信号处理程序退出,程序为何继续运行?
看起来当我的信号处理程序结束时,我的程序仍然在继续运行。这一点很明显,因为即使在“日志完成,现在关闭”之后,仍然会出现异常。有人能解释一下这是为什么吗?请注意,这些函数已经简化了。
^Clog Ctrl-C
backup State: not_span 328, pos 22, all_cycles 19
backup backup complete, you may force exit now
log Done, close now
Traceback (most recent call last):
File "singleEdger.py", line 219, in <module>
mySingleEdger.outputAllCycles()
File "singleEdger.py", line 141, in outputAllCycles
r = self.returnCycle( self.dfs_tree, self.not_span[self.pos])
File "singleEdger.py", line 72, in returnCycle
udfs = nx.Graph(dfs) # The trick is to make it undirected
File "/var/lib/python-support/python2.6/networkx/graph.py", line 86, in __init__
convert.from_whatever(data,create_using=self)
File "/var/lib/python-support/python2.6/networkx/convert.py", line 76, in from_whatever
"Input is not a correct NetworkX graph."
networkx.exception.NetworkXError: Input is not a correct NetworkX graph.
这些是供参考的函数
def sigHandler(self, arg1, arg2):
out('log', 'Ctrl-C')
self.backup()
out('log', 'Done, close now')
exit()
def outputAllCycles(self):
while self.pos < len(self.not_span):
r = self.returnCycle( self.dfs_tree, self.not_span[self.pos])
if r:
self.all_cycles.append( r )
for each in r: # now it's [ (3,4), (5,6) ]
each = (sellHash(each[0]), sellHash( each[1]) )
self.outfo.write( each[0] +'\t'+ each[1] )
self.outfo.write( '\n')
self.outfo.write( '\n')
self.pos += 1
out( "singleEdger", "outputAllCycles done")
def backup(self):
out( 'backup', 'State: not_span %i, pos %i, all_cycles %i' % ( len(self.not_span), self.pos, len(self.all_cycles)) )
out( 'backup', 'backup complete, you may force exit now')
3 个回答
当你在运行代码时按下 ^C(通常是用来停止程序的快捷键),如果你的代码周围有一个 try/except 块,那么这个操作可能不会生效,因为 exit() 实际上会引发一个异常。你可以查看这个链接了解更多信息:http://bugs.python.org/issue8021
这种情况即使发生在你调用的库代码中,而不是你自己写的代码里,也同样适用。我在为一个机器人编写代码时,使用 urllib2.urlopen 在循环中连接网址时注意到了这一点;urllib2 的 do_open() 函数在尝试连接网址的代码周围也使用了 try/except 块。
还有一点你需要注意的是,在信号处理器中尽量避免进行耗时的操作(比如调用 backup()
可能会耗时很长)。更好的做法是设置一个标志,先从信号处理器返回,然后再进行处理。原因是(在Python中)信号处理器仍然会被注册,如果后续收到同类型的信号,它会打断当前的信号处理器,导致它再次执行。这可能不是你想要的结果。
或者你可以在处理器中忽略这个信号,比如:
import signal
def sigHandler(sig, frame):
oldHandler = signal.signal(sig, signal.SIG_IGN)
backup() # lengthy processing here...
signal.signal(sig, oldHandler)
但要注意,这样只会忽略同样的信号,其他信号仍然可能会打断你的处理。你的 backup()
是可重入的吗?
关于可重入性的讨论是相关的,虽然它是针对C语言的,而Python有些不同,比如信号不能被阻塞(除非你使用 ctypes
)。
我觉得你的代码可能没有在运行。虽然异常输出的位置在代码中,但并不能保证它会在你最后的打印信息之前出现。异常输出是发送到错误输出(STDERR)的,而你的打印语句是发送到标准输出(STDOUT)的;在这个例子中,它们恰好都是写入同一个终端设备。两者的输出是独立缓冲的,所以输出的顺序并不是固定的;也就是说,你不能根据输出的相对位置来推断任何事情。
如果你在单元测试中放入打印语句,你也会看到同样的现象。