asyncio - 如何在信号处理程序中使用协同程序?

时间:2014-04-26 16:35:00

标签: python signals coroutine python-asyncio

我正在开发一个使用python3.4的asyncio进行网络连接的应用程序。当此应用程序干净地关闭时,节点需要与集线器“断开连接”。此断开连接是一个需要网络连接的活动进程,因此循环需要在关闭之前等待此操作完成。

我的问题是使用协同程序作为信号处理程序将导致应用程序不关闭。请考虑以下示例:

import asyncio
import functools
import os
import signal

@asyncio.coroutine
def ask_exit(signame):
    print("got signal %s: exit" % signame)
    yield from asyncio.sleep(10.0)
    loop.stop()

loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
    loop.add_signal_handler(getattr(signal, signame),
                                        functools.partial(ask_exit, signame))

print("Event loop running forever, press CTRL+c to interrupt.")
print("pid %s: send SIGINT or SIGTERM to exit." % os.getpid())
loop.run_forever()

如果您运行此示例然后按Ctrl + C,则不会发生任何事情。 问题是,如何使用siganls和coroutines来实现这种行为?

3 个答案:

答案 0 :(得分:9)

python的语法> = 3.5

loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
    loop.add_signal_handler(getattr(signal, signame),
                            lambda: asyncio.ensure_future(ask_exit(signame)))

答案 1 :(得分:4)

loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
    loop.add_signal_handler(getattr(signal, signame),
                            asyncio.async, ask_exit(signame))

这样信号会导致你的ask_exit被安排在任务中。

答案 2 :(得分:1)

python3.8

  • 第一次尝试:使用async def handler_shutdown,并在传递给loop.create_task()时将其包裹在add_signal_handler()
  • 第二次尝试:不要对def handler_shutdown()使用异步。
  • 第三次尝试:将handler_shutdown和param包装在functools.partial()

例如

import asyncio
import functools
def handler_shutdown(signal, loop, tasks, http_runner, ):
    ...
    ...
def main():
    loop = asyncio.get_event_loop()
    for signame in ('SIGINT', 'SIGTERM', 'SIGQUIT'):
                print(f"add signal handler {signame} ...")
                loop.add_signal_handler(
                    getattr(signal, signame),
                    functools.partial(handler_shutdown,
                            signal=signame, loop=loop, tasks=tasks,
                            http_runner=http_runner
                            )
                    )
  • 我遇到的主要问题是错误

    raise TypeError("coroutines cannot be used "

  • 通过将例程包装在loop.create_task()

  • 中解决了该问题
  • 然后通过删除异步表单信号处理程序函数来解决此问题
  • 对于处理程序的命名参数,也使用functools.partial