Pylons中的信号处理
我有一个使用pylons框架的项目,需要定期更新一些内存中的数据结构。这些更新应该是根据需要进行的。于是我决定为此创建一个信号处理器。用户可以向主pylons线程发送SIGUSR1
信号,项目会处理这个信号。
这个方法是可行的,但在处理完信号后,服务器会崩溃,并出现以下异常:
File "/usr/lib/python2.6/SocketServer.py", line 264, in handle_request
fd_sets = select.select([self], [], [], timeout)
select.error: (4, 'Interrupted system call')
有没有办法解决这个问题呢?
谢谢大家。
2 个回答
2
这是一个解决方法,至少对我有效,来自一个12年前的python-dev邮件列表帖子
while True:
try:
readable, writable, exceptional = select.select(inputs, outputs, inputs, timeout)
except select.error, v:
if v[0] != errno.EINTR: raise
else: break
其实,具体的选择行并不重要……你的“fd_sets = select.select([self], [], [], timeout)”这一行应该是完全可以正常工作的。
关键是要检查是否出现了EINTR错误,如果捕捉到这个错误,就要重试或者循环执行。哦,对了,别忘了导入errno模块。
5
是的,这个是可以做到的,但用普通的Python库实现起来并不简单。这是因为Python会把所有操作系统的错误都转化为异常。不过,EINTR这个错误其实应该让你重新尝试之前的系统调用。每当你在Python中使用信号时,你都会偶尔遇到这个错误。
我有一段代码可以解决这个问题(叫做SafeSocket),它通过分叉Python模块来添加这个功能。不过,这个功能需要在每个使用系统调用的地方都加上去。所以说,虽然可以做到,但并不容易。不过你可以使用我的开源代码,这样可能会省去你几年的工作。;-)
基本的模式是这样的(实现为一个系统调用的装饰器):
# decorator to make system call methods safe from EINTR
def systemcall(meth):
# have to import this way to avoid a circular import
from _socket import error as SocketError
def systemcallmeth(*args, **kwargs):
while 1:
try:
rv = meth(*args, **kwargs)
except EnvironmentError as why:
if why.args and why.args[0] == EINTR:
continue
else:
raise
except SocketError as why:
if why.args and why.args[0] == EINTR:
continue
else:
raise
else:
break
return rv
return systemcallmeth
你也可以把这个装饰器用在你的select调用周围。