通过 SIGTERM 间接停止 python asyncio 事件循环无效

Indirectly stopping a python asyncio event loop through SIGTERM has no effect

以下最小程序重现了该问题。

import asyncio
import signal

class A:
    def __init__(self):
        self._event_loop = asyncio.new_event_loop()

    def run(self):
        print('starting event loop')
        self._event_loop.run_forever()
        print('event loop has stopped')

    def stop(self):
        print('stopping event loop')
        self._event_loop.stop()


if __name__ == '__main__':
    a = A()

    def handle_term(*args):
        a.stop()

    signal.signal(signal.SIGTERM, handle_term)
    a.run()

如果您 运行 程序并向进程发送 SIGTERM,将调用第 16 行中的打印语句(停止事件循环)但程序不会终止,并且第 13 行中的打印语句(事件循环已停止)永远不会被调用。所以似乎事件循环永远不会停止并且 self._event_loop.run_forever() 无限期地阻塞。

这是为什么?

注意:程序的修改版本,其中 a.stop() 不是由信号处理程序调用,而是由具有延迟的单独线程调用,按预期工作。 a.stop() 的称呼方式有何不同?

而不是 signal.signal() 使用 loop.add_signal_handler():

import asyncio
import signal

import os


class A:
    def __init__(self):
        self.loop = asyncio.new_event_loop()
        self.loop.add_signal_handler(signal.SIGTERM, self.stop)

    def stop(self):
        print('stopping')
        self.loop.stop()

    def run(self, close=True):
        print('starting loop')
        try:
            self.loop.run_forever()
            print('loop stopped')
        finally:
            if close:
                self.loop.close()


if __name__ == '__main__':
    print("to stop run:\nkill -TERM {}".format(os.getpid()))
    a = A()
    a.run()