python解释和信号处理程序

gstyhher  于 2023-10-21  发布在  Python
关注(0)|答案(2)|浏览(199)

我有这段代码来测试Pencio是如何工作的:

stop = False

async def subcoro():
    # same result even with a range of 30
    for i in range(30000):
        pass

async def first():
    global stop
    while not stop:
        await subcoro()
        # without sleep no signal is triggered
        await asyncio.sleep(0.1)

async def main(loop):
    coro = asyncio.ensure_future(first())
    await asyncio.wait([coro], loop=loop)

def end():
    global stop
    stop = True

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    for signame in ('SIGINT', 'SIGTERM'):
        loop.add_signal_handler(getattr(signal, signame), end)
    try:
        loop.run_until_complete(asyncio.ensure_future(main(loop)))
    finally:
        loop.close()
        print('Bye!')

为什么我必须让first()休眠一段时间(甚至小于0.1)才能让程序处理信号?有没有其他方法可以优雅地关闭所有协程和事件循环?
更新:在python-forum.org上,他们告诉我在PEP-0492上阅读,但没有提供任何解决方案或建议。
客户2:我的真实的应用程序:https://github.com/FedericoTorsello/Embedded/tree/serialIO

zsbz8rwp

zsbz8rwp1#

我喜欢这个问题,我尝试的第一件事是strace都:
对于sleep,我看到了很多epoll(等待信号,通过套接字“转发”,通常是为了遵守处理接收信号所需的原子性)。
如果没有sleep,就没有epoll,所以信号被进程接收,信息被推到套接字上,但永远不会读取。
为什么会这样?从语义学的Angular 来看,

while not stop:
    await subcoro()

是“牢不可破”的,
await类似于yield from,挂起[the]协程的执行,直到[the] awaitable完成并返回结果数据。
但是由于您的subcoro没有给予循环,它将“立即”返回,因此“await”得到满足,循环再次循环,永远不会给主循环追赶的机会。
所以你真的在一个“无限的while循环”中,永远不会把手还给主循环。
现在,使用asyncio.sleep,您可以将手交还给主循环,因为很明显,asyncio.sleep的实现可以做到这一点,因此主循环可以在睡眠期间做其他事情,例如检查网络事件,例如套接字上接收的信号。还有另一种方式来显式地将手给予循环,是一个空的“yield”,比如:

@asyncio.coroutine
def cooperate():
    yield
    return

现在,调用await cooperate()与不实际休眠的await asyncio.sleep(0.1)具有相同的效果,这是asyncio.sleep在给定0延迟时的情况:

@coroutine
def sleep(delay, result=None, *, loop=None):
    """Coroutine that completes after a given time (in seconds)."""
    if delay == 0:
        yield
        return result
    [...]

从实施的Angular 来看,现在:
在sleep中,asyncio.base_events.BaseEventLoop._run_once会被反复调用,但在没有sleep的情况下永远不会返回,可能是因为你的first永远不会返回它,我没有深入检查它。
总结如下:subcoro按原样是没有意义的,在真实的世界应用中,它会给主循环回给予一些时间,通常是通过调用网络,或者等待任何东西。

n1bvdmb6

n1bvdmb62#

Since loop. add.. sig调用的函数/处理程序可以在信号处理期间与循环交互(不需要显式地传递它或其他参数,如seen doc)。按照lib aiohttp/gunicorn eg,在所有coros except CustmException:子句中引发CustomException()并清理。范例:

import asyncio # etc

class GracefulExit(SystemExit):
    def __init__(self, msg=None, code=None):
        super(GracefulExit, self).__init__(msg)
        self.code = code

def handle_SIGTERM_exit(signum):
    logging.debug(f'handle {signal.Signals(signum)!r}')
    raise GracefulExit(code=0) # https://docs.python.org/3/library/asyncio-eventloop.html#set-signal-handlers-for-sigint-and-sigterm

def handle_SIGABRT_exit(signum): # else Fatal Python error: Aborted
    raise GracefulExit(code=1)

async def main():
    loop = asyncio.get_event_loop()
    loop.add_signal_handler(signal.SIGTERM, functools.partial(handle_SIGTERM_exit, signal.SIGTERM)) 
    loop.add_signal_handler(signal.SIGABRT, handle_SIGABRT_exit, signal.SIGABRT, None)
    # add other coros to loop (that catch or finally:) 

asyncio.run(main())

相关问题