使用 Starlette 和 Uvicorn 进行 Python 日志记录时文件句柄过多(在 lsof 上)

Cod*_*ght 8 python logging lsof starlette uvicorn

我有一个通过 uvicorn 运行的最小 starlette 应用程序,除了返回一个 ping 什么都不做。奇怪的是,即使只有一个线程,我的日志文件也有 45 个文件句柄。句柄随着对应用程序的点击而增加,并在 45 处保持平稳。我正在使用 lsof 计算文件句柄:

lsof | grep kml-bkny.log
Run Code Online (Sandbox Code Playgroud)

当然,这是最小的再生产。实际上,我的整个应用程序正在生成数千个文件句柄。一些(~200)我希望给定线程*控制器模块。但是,我无法解释在何处创建了数千个文件句柄。在我的实际程序中,它们也不会停滞不前,它们会永远增长。

这是我的应用程序(api.py):

import logging

from starlette.applications import Starlette
from starlette.responses import JSONResponse

logger = logging.getLogger("kml")
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler('/tmp/kml-bkny.log')
logger.addHandler(handler)

def controller_ping(request):
    try:
        logger.debug("Received /ping request")
        return JSONResponse({}, status_code=200)
    except Exception as e:
        logger.error(e)
        return JSONResponse({}, status_code=500)

app = Starlette()
app.add_route(path='/kml/ping', methods=['GET'], route=controller_ping)
Run Code Online (Sandbox Code Playgroud)

我在命令行上运行它,如下所示:

uvicorn api:app
Run Code Online (Sandbox Code Playgroud)

我使用一个简单的脚本测试应用程序:

import time
import requests

while True:
    time.sleep(1)
    for _ in range(10):
        r = requests.get(f'http://localhost:8000/kml/ping', timeout=5)
Run Code Online (Sandbox Code Playgroud)

它在 Ubuntu 18.04 上运行,starlette==0.13.3 和 uvicorn==0.11.3 在 Python 3.6 上

作为对比,在不带starlette+uvicorn的情况下运行没有这种效果。以下控制程序将在 lsof 上生成 2 个且仅 2 个文件句柄:

import logging
import time

logger = logging.getLogger("kml")
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler('/tmp/kml-bkny.log')
logger.addHandler(handler)

while True:
    time.sleep(1)
    for _ in range(10):
        logger.debug("Received /ping request")
Run Code Online (Sandbox Code Playgroud)

为什么在介绍 starlette 和 uvicorn 时会在 lsof 上看到创建这么多文件句柄?