为什么Django request.user.is_authenticated 需要8秒才能执行?

时间:2021-04-17 18:31:34

标签: python django

我完全糊涂了。几天前,我的 Django 应用开始运行速度明显变慢。

原来是下面的Django视图需要

  • 8 秒对授权查看者执行
  • 0 秒为匿名用户执行
def speed_test(request):

    start = time.time() # measuring execution time 

    b = request.user.is_authenticated  # THIS somehow creates a problem

    response = {"test": "test"} # constructing a dummy response

    end = time.time() 
    logger.warning("speed test: " + str(end - start) + " auth = " + str(b)) # logging

    return HttpResponse(json.dumps(response))
17/Apr/2021 17:18:18 WARNING speed test: 8.06065821647644 auth = True
17/Apr/2021 17:23:04 WARNING speed test: 6.508827209472656e-05 auth = False

is_authenticated 可以被 AbstractBaseUser 中的任何函数替换,结果相同。 如果我删除对 is_authenticated 的调用,对于每个用户来说一切都会很快。

使用runservergunicorn/uwsgi复制它。

但我无法在我的开发笔记本电脑上重现它,即使连接到同一个远程数据库。所以看起来不像是数据库问题,也绝对不是网络问题。

Django 3.08、python 3.8、ubuntu。尝试制作全新的 venv - 无济于事。

数据库连接尽可能默认:

DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': 'user',
            'USER': 'user',
            'PASSWORD': 'password',
            'HOST': 'hostname',
            'PORT': '5432',
        }

}

如果您能提供有关如何解决此问题的任何提示,我将不胜感激。

2 个答案:

答案 0 :(得分:1)

Django 延迟加载 request.user 以便根据身份验证状态它可以是​​ User 或 AnonymousUser 。它仅在访问属性时“唤醒”并返回适当的类。在这种情况下,我们正在调用 is_authenticated 属性,现在它必须调用数据库进行检查。在您的情况下,对 db 的查询很可能需要很长时间。

答案 1 :(得分:1)

request.user 是一个惰性属性。这意味着 Django 将获取登录的用户对象,除非你真的需要它。

如果您因此使用 request.user.is_authenticated,那么这将需要对数据库进行查询以获取用户对象。如果没有与登录用户的会话,那么检索 request.user 会很快,因为它甚至不会查询数据库:如果会话 ID 的会话数据丢失,它将简单地返回 { {1}} 个对象。

如果这是系统进行的第一个查询,情况会更糟,因为那时没有打开的连接,因此可能需要额外的逻辑来首先连接到数据库。尤其是众所周知,PostgreSQL 在打开连接方面非常昂贵。

Django 通常会使用一个连接池的开放连接,并为新查询重用连接。但如果这是第一次查询,则池通常是空的,因此打开连接并进行查询需要一些努力。