简体   繁体   English

通过SIGTERM间接停止python asyncio事件循环没有任何效果

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

The following minimal program reproduces the problem. 以下最小程序重现了该问题。

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()

If you run the program and send a SIGTERM to the process, the print statement in line 16 (stopping event loop) is called but the programm does not terminate and the print statement in line 13 (event loop has stopped) is never called. 如果运行程序并将SIGTERM发送到进程,则会调用第16行(停止事件循环)中的print语句,但程序不会终止,并且永远不会调用第13行中的print语句(事件循环已停止)。 So it seems that the event loop is never stopped and self._event_loop.run_forever() blocks indefinitely. 所以似乎事件循环永远不会停止, self._event_loop.run_forever()无限期地阻塞。

Why is this? 为什么是这样?

Note: A modified version of the program, where a.stop() is not called by a signal handler but by a seperate thread with a delay, works as expected. 注意:程序的修改版本,其中a.stop()不是由信号处理程序调用,而是由具有延迟的单独线程调用,按预期工作。 How can it make a difference how a.stop() is called? 如何调用a.stop()什么不同?

Instead of signal.signal() use loop.add_signal_handler() : 而不是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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM