Python 在睡眠循环中实现信号处理
我正在开发的一个应用程序中的一个模块打算在Linux上用作一个长期运行的进程,我希望它能够优雅地处理SIGTERM、SIGHUP以及可能的其他信号。程序的核心部分实际上是一个循环,它周期性地运行一个函数(这反过来会唤醒另一个线程,但这并不重要)。它看起来或多或少像这样:Python 在睡眠循环中实现信号处理,python,unix,signals,sleep,busy-waiting,Python,Unix,Signals,Sleep,Busy Waiting,我正在开发的一个应用程序中的一个模块打算在Linux上用作一个长期运行的进程,我希望它能够优雅地处理SIGTERM、SIGHUP以及可能的其他信号。程序的核心部分实际上是一个循环,它周期性地运行一个函数(这反过来会唤醒另一个线程,但这并不重要)。它看起来或多或少像这样: while True: try: do_something() sleep(60) except KeyboardInterrupt: break cleanu
while True:
try:
do_something()
sleep(60)
except KeyboardInterrupt:
break
cleanup_and_exit()
我现在要添加的是捕获SIGTERM并退出循环,就像键盘中断
异常一样
我的一个想法是添加一个标志,该标志将由信号处理程序函数设置为True,并将睡眠(60)替换为睡眠(0.1)或其他类型,使用计数秒的计数器:
_exit_flag = False
while not _exit_flag:
try:
for _ in xrange(600):
if _exit_flag: break
do_something()
sleep(0.1)
except KeyboardInterrupt:
break
cleanup_and_exit()
在其他地方:
def signal_handler(sig, frame):
_exit_flag = True
但我不确定这是最好/最有效的方法 与其在主循环中使用哨兵,因此必须比您真正想要检查的更频繁地唤醒,为什么不将清理工作推到处理程序中呢?比如:
class BlockingAction(object):
def __new__(cls, action):
if isinstance(action, BlockingAction):
return action
else:
new_action = super(BlockingAction, cls).__new__(cls)
new_action.action = action
new_action.active = False
return new_action
def __call__(self, *args, **kwargs):
self.active = True
result = self.action(*args, **kwargs)
self.active = False
return result
class SignalHandler(object):
def __new__(cls, sig, action):
if isinstance(action, SignalHandler):
handler = action
else:
handler = super(SignalHandler, cls).__new__(cls)
handler.action = action
handler.blocking_actions = []
signal.signal(sig, handler)
return handler
def __call__(self, signum, frame):
while any(a.active for a in self.blocking_actions):
time.sleep(.01)
return self.action()
def blocks_on(self, action):
blocking_action = BlockingAction(action)
self.blocking_actions.append(blocking_action)
return blocking_action
def handles(signal):
def get_handler(action):
return SignalHandler(signal, action)
return get_handler
@handles(signal.SIGTERM)
@handles(signal.SIGHUP)
@handles(signal.SIGINT)
def cleanup_and_exit():
# Note that this assumes that this method actually exits the program explicitly
# If it does not, you'll need some form of sentinel for the while loop
pass
@cleanup_and_exit.blocks_on
def do_something():
pass
while True:
do_something()
time.sleep(60)
当然,我没有提到信号处理器通过
signal.signal
连接到正确的信号。你可以在收到另一个信号时触发键盘中断(SIGINT)。谢夫伦,这个问题仍然相关吗?对我来说不相关,但如果你有更好的答案,它可能对其他人有用