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

Max*_*Tet 5 python python-asyncio

下面的最小程序重现此问题。

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()
Run Code Online (Sandbox Code Playgroud)

如果运行程序并将SIGTERM发送给该进程,则将调用第16行中的print语句(停止事件循环),但程序不会终止,并且永远不会调用第13行中的print语句(事件循环已停止)。因此,似乎事件循环永远不会停止并且self._event_loop.run_forever()无限期地阻塞。

为什么是这样?

注意:程序的修改版本a.stop()可以按预期工作,而不是由信号处理程序调用,而是由具有延迟的单独线程调用。如何能有所作为怎么a.stop()叫?

Udi*_*Udi 5

而不是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()
Run Code Online (Sandbox Code Playgroud)