我有一小段代码
import asyncio
from aiohttp import web
from multiprocessing import Process
import time
def block():
i = 0
while i < 5:
print('running')
time.sleep(1)
i += 1
async def start(request):
process = Process(target=block)
process.start()
print('process started')
request.app['p'] = process
return web.Response(status=200)
async def stop(request):
if request.app['p'].is_alive():
print('stop process')
request.app['p'].terminate()
return web.Response(status=200)
app = web.Application()
app.router.add_route('GET', '/start', start)
app.router.add_route('GET', '/stop', stop)
web.run_app(app, host='127.0.0.1', port=8888)
当我在
/start
上发送 HTTP GET 时,我可以看到 running
每秒都在终端上输出,就像预期的那样。但是当我在 /stop
上发送 HTTP GET 时,running
的流在循环完成之前不会停止。此外,当循环结束时,整个应用程序就会死亡。
这是这个的输出:
❯ python3 server.py
======== Running on http://127.0.0.1:8888 ========
(Press CTRL+C to quit)
process started
running
running
running
stop process
running
running
❯
有趣的是,这个请求处理程序可以在不停止整个应用程序的情况下工作。
async def stop2(request):
if request.app['p'].is_alive():
print('stop2 process')
os.kill(request.app['p'].pid, signal.SIGKILL)
return web.Response(status=200)
那么在python/aiohttp中使用
os.kill
和process.terminate
有什么区别呢? 最佳答案
区别在于 terminate()
发送 SIGTERM
信号,而 kill()
发送您指定的信号。
默认情况下,Aiohttp 在启动时为 SIGTERM
和 SIGINT
注册处理程序,以便正常关闭。在生产环境中,您通常不会在控制台中运行您的应用程序(因此您无法使用 Ctrl+C 禁用它),而是使用一些进程主管,如 Systemd 或 Docker。要停止此类应用程序,主管通常会发送 SIGTERM
。您可以使用 arg handle_signals=False
到 run_app()
调用禁用默认处理程序,但是当您决定关闭服务器时,这些信号中的任何一个都会立即被杀死。
当您在 UNIX 上使用 multiprocessing
模块时,您的子进程是通过 fork()
调用创建的——这意味着,在创建时,它几乎是主进程的完整副本——并且它有一个父信号处理程序的副本。使用 subprocess
模块对此有所帮助 - 您将拥有从头开始制作的全新 python 进程,无需父处理程序。或者您可以恢复默认处理程序,如果您将这些行添加到 block()
调用的开头:
signal.set_wakeup_fd(-1)
signal.signal(signal.SIGTERM, signal.SIG_DFL)
通常,信号仅被一个进程使用(您在
kill()
中指定其 pid)。但是使用 aiohttp 会发生一些神奇的事情。 asyncio
的底层实现使用 signal.set_wakeup_fd()
函数来处理信号,这使得信号被写入套接字。这使得信号只是 asyncio 事件循环的标准事件。但这是您的应用程序中断的地方。不仅您的工作进程没有停止(因为 aiohttp 中断了信号)。由于套接字是在 fork()
调用之前创建的,因此它在您的主进程和所有子进程之间共享。因此,任何发送给子进程的 SIGTERM
和 SIGINT
信号都将由主进程处理。在 /stop
请求之后,您的网络服务器已经死机 - 甚至在循环完成之前。关于python-3.x - aiohttp 中的 os.kill 与 process.terminate,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50781181/