Posted on:
Last modified:
昨天写了一个服务,在本地运行很好,使用 Ctrl-C
结束运行之后会清理资源,然后取消注册,然而
放到 Docker 中跑之后发现结束之后资源没有释放。查了查发现原来是下面是几个因素造成的:
Ctrl-C
发送的是 SIGINT 信号,Python 会转化成 KeyboardInterrupt
异常,而我的资源是在
finally 释放资源,所以使用 Ctrl-C
可以优雅地退出所以在 docker stop 的时候服务会直接挂掉。和 docker 类似,systemctl 还会发送 SIGHUP 信号。
可以使用 signal 模块,注册一个 SIGTERM 的 handler,把 SIGTERM 转换成普通的异常就行啦, 这样在退出时也会运行 finally 子句中的语句。
import signal
def handler(signum, frame):
raise KeyboardInterrupt
signal.signal(signal.SIGTERM, handler)
signal.signal(signal.SIGHUP, handler)
下面再介绍一下 signal 模块中的其他用法。
signal.signal(SIGXXX, handler)
为 SIGXXX 设置处理函数,handler 函数接收两个参数,signum 和 frame.
signal 模块还内置了两个处理函数,可以用作 signal.signal 的参数。
signal.SIG_DFL
,执行系统的默认处理函数。比如说,SIGQUIT
会导致 coredump 并退出,SIGCHLD
则会忽略,不做任何操作。
signal.SIG_IGN
,直接忽略信号
signal.alarm
可以使子线程有能力通知主线程退出,也可以给潜在的堵塞型操作一个退出的机会。
每个线程都可以执行 alarm
, getsignal
, pause
, setitimer
和 getitimer
函数,但是
只有主线程可以设置新的信号处理函数,也只有主线程会接受到信号。
import signal, os
def handler(signum, frame):
print('Signal handler called with signal', signum)
raise IOError("Couldn't open device!")
# 设置一个 5s 的 alarm,即使 hang 住,也会有机会跳出
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)
try:
# 这个文件打开操作可能会无限 hang 住
fd = os.open('/dev/ttyS0', os.O_RDWR)
except IOError:
pass
signal.alarm(0) # Disable the alarm
© 2016-2022 Yifei Kong. Powered by ynotes
All contents are under the CC-BY-NC-SA license, if not otherwise specified.
Opinions expressed here are solely my own and do not express the views or opinions of my employer.
友情链接: MySQL 教程站