第十章:使用进程、线程和协程提供并发性-asyncio:异步I/O、事件循环和并发工具-接收UNIX信号
10.5.13 接收UNIX信号
UNIX系统事件通知通常会中断一个应用,触发它们的处理器。结合asyncio使用时,信号处理器回调会与事件循环管理的其他协程和回调交叉执行。这种集成会更少地中断函数,尽可能减少提供防护来清理未完成的操作的需要。
信号处理器必须是常规的callable,而不是协程。
import asyncio
import functools
import os
import signal
def signal_handler(name):
print('signal_handler({!r})'.format(name))
# 信号处理器用add_signal_handler()注册。第一个参数是信号;第二个参数是回调。不
# 向回调传递任何参数,所以如果需要参数,可以用functools.partial()包装一个函数。
event_loop = asyncio.get_event_loop()
event_loop.add_signal_handler(
signal.SIGHUP,
functools.partial(signal_handler,name='SIGHUP'),
)
event_loop.add_signal_handler(
signal.SIGUSR1,
functools.partial(signal_handler,name='SIGUSR1'),
)
event_loop.add_signal_handler(
signal.SIGINT,
functools.partial(signal_handler,name='SIGINT'),
)
# 这个示例程序使用了一个协程通过os.kill()向自身发送信号。发送各个信号之后,协程
# 交出控制,从而允许这个处理器运行。在一个真是的应用中,可能有更多位置上的应用
# 代码会把控制交回给事件循环,所以不需要(像这个例子中一样)人为地交出控制。
async def send_signals():
pid = os.getpid()
print('starting send_signals for {}'.format(pid))
for name in ['SIGHUP','SIGHUP','SIGUSR1','SIGINT']:
print('sending {}'.format(name))
os.kill(pid,getattr(signal,name))
# Yield control to allow the signal handler to run,
# since the signal does not interrupt the program
# flow otherwise.
print('yielding control')
await asyncio.sleep(0.01)
return
# 主程序运行send_signals(),直到已经发出所有信号。
try:
event_loop.run_until_complete(send_signals())
finally:
event_loop.close()
输出显示了发送一个信号后send_signals()交出控制时如何调用处理器。