【问题标题】:Indirectly stopping a python asyncio event loop through SIGTERM has no effect通过 SIGTERM 间接停止 python asyncio 事件循环没有效果
【发布时间】:2017-03-07 04:40:11
【问题描述】:

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

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() 的调用方式有何不同?

【问题讨论】:

    标签: python python-asyncio


    【解决方案1】:

    loop.add_signal_handler()代替signal.signal()

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

    【讨论】:

    • 我现在就是这样解决的。但我不喜欢它。它将在 A 类的事件循环中运行的逻辑与它的停止方式相结合。从架构上讲,将这两者分开并让 A 的事件循环从 A 外部停止会更干净。另外:我仍然很好奇为什么我的示例不起作用。据我了解,它应该可以工作,对吧?
    • 您可以使用faulthandler.dump_traceback()查看您的程序卡在select()中。 Unix 需要使用signal.set_wakeup_fd() 来唤醒 poll/select。
    猜你喜欢
    • 1970-01-01
    • 2013-04-26
    • 2022-12-22
    • 1970-01-01
    • 2017-01-05
    • 1970-01-01
    • 2020-05-05
    • 2020-11-28
    • 1970-01-01
    相关资源
    最近更新 更多