接收Unix信号
Unix系统事件通知通常会中断应用程序,触发其处理程序。当与asyncio一起使用时,信号处理程序回调会与事件循环管理的其他协程和回调交错。这导致中断的功能更少,因此需要提供安全防护来清理不完整的操作。信号处理程序必须是常规可回调函数,而不是协程。
1 2 3 4 5 6 7 8
| import asyncio import functools import os import signal def signal_handler(name): print('signal_handler({!r})'.format(name))
|
信号处理程序使用add_signal_handler()注册。第一个参数是信号,第二个是回调函数。回调函数没有参数,因此如果需要参数,函数可以用functools.partial()来包装。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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()向自己发送信号。在发送每个信号之后,协程会让出控制权以允许处理程序运行。在一个正常的应用程序中,应用程序代码将控制权交给事件循环的地方会更多,并且不需要像这样的人工交出控制权。
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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)) print('yielding control') await asyncio.sleep(0.01) return
|
主程序运行send_signals(),直到它发送了所有的信号。
1 2 3 4
| try: event_loop.run_until_complete(send_signals()) finally: event_loop.close()
|
输出显示send_signals()在发送信号后交出控制权时如何调用处理程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| $ python3 asyncio_signal.py starting send_signals for 21772 sending SIGHUP yielding control signal_handler('SIGHUP') sending SIGHUP yielding control signal_handler('SIGHUP') sending SIGUSR1 yielding control signal_handler('SIGUSR1') sending SIGINT yielding control signal_handler('SIGINT')
|
本文翻译自《The Python3 Standard Library By Example》asyncio相关章节