【问题标题】:Django - waiting time for a particular view in production takes too longDjango - 生产中特定视图的等待时间太长
【发布时间】:2011-05-18 19:47:53
【问题描述】:

我至少两天以来一直在努力解决这个问题。 有一个视图会生成一个页面,显示某个用户/电话分机拨打的所有电话。没什么花哨的,就是一页很长,最多 1000 行。

此视图函数从 url 接收一些参数,以便选择在此页面上显示的内容。有两种情况,一种是传递了“extension=xxxxxx”,一种是url中传递了“user=xxxx”:

if request.GET.get("extension", None):
    # extension_query expects only one Extension object
    extension_query = Extension.objects.filter(number=request.GET["extension"])
    ... # Here I do some conditionals to match the right Extension object.
elif request.GET.get("user", None):
    ... # Simple stuff, nothing to significant.
# at the end I call render_to_response normally

编辑 - 这是调用我自定义的 render_to_response 的一段代码:
Edit2 - 在 John C 建议强制评估查询集之后,加载时间从 1.6 分钟减少到 14 秒:现在我投在将 list() 传递给我的自定义 render_to_response 之前,我对它的调用:

if (request.GET.get("format", None) == "screen"
    or request.GET.get("print", False)):
    ctx = dict(calls=list(calls), client=client, extension=extension,
               no_owner_extension=no_owner_extension,
               start=start_date, end=end_date, tab="clients",
               owner=user)
    return finish_request(
        request, "reports/exporting_by_call_type.html", ctx)

这是我自定义的 render_to_response:

def finish_request(request, template, context):
    if "print" in request.GET or "print" in request.POST:
        context.update(printing=True)
    return render_to_response(
        template, RequestContext(request, context))

在我的开发机器中,根据 Chrome 对 BOTH 情况的审核,需要 3-4 秒才能完全处理此视图以获得真实的数据场景。在生产环境中,需要 3-4 秒来加载在 URL 中传递 user 参数的视图,但是当传递 extension 时,需要 2 分钟!

编辑:重要的是要说在 URL 中传递 userextension 之间的区别不会改变最终呈现的页面,除了顶部的一行我指示分机号码何时属于某人。其余数据完全相同。

我分析了我的代码中与生成此视图有关的每个小块。我在我的生产代码中计时了视图到 render_to_response 的时间(0.05 秒)。我取出了在我的模板中调用 extension 但没有成功的部分。我还使用 django_debug_toolbar 来查看每个 SQL 语句在做什么,并且查询最多需要 2 秒。

我还应该补充一点,我在生产设置中使用了 mod_wsgi,debug=False... 尽管花费了 2 分钟,YSlow 仍将此页面评为 94。

谁能解释一下?

【问题讨论】:

  • 次要注意 - 在浏览 Django 文档时,我注意到 repr() Queryset 函数,它强制评估查询集,但没有将其转换为列表。如果您(或某人)不想要 list,但仍想强制评估查询集,这是一个选项。

标签: django django-views


【解决方案1】:

我看不出该代码有什么明显错误。我有一个问题,您是否期望 one 对象完全匹配?如果是这样,可能值得尝试这段代码:

getData = request.GET.copy() # optional, I like my own copy.
if 'extension' in getData:
    ext = getData['extension']
    extObj = Extension.objects.get(number__exact=ext) # double-underline
# elif...

请注意,这将导致扩展对象,而不是查询集。如果你有多个扩展,那么你确实需要使用 filter - 但我仍然建议使用 exact,以及移动 ext 的阅读em> 从字典到 filter 语句之外。

更新(来自我的 cmets) - 尝试使用对 list() 的调用强制立即评估 Queryset,看看这是否对 render_to_response 有影响。

更新 2 - 因为它确实 产生了影响 - 这就是我 认为 可能发生的事情。由于 Django 查询集使用惰性求值,因此当模板最终执行时 - 它调用的是迭代器,而不是现有列表。也许有太多的函数调用正在进行,每次调用迭代器来获取一个新值,都会产生很多不必要的开销。或者,也许有一个错误。 :)

【讨论】:

  • 我希望完全匹配一个扩展对象。实际上,一旦我得到“extension_query”来匹配正确的扩展名,我就会做更多的事情。让我感到不安的是,我确信我的整个功能只需不到一秒钟的时间就可以完全处理完毕。这是在 render_to_response 之后发生的事情,需要很长时间。
  • @chiurox,也许值得将 render_to_response 代码添加到您的帖子中?此外 - 可能值得尝试强制立即评估查询集,例如 len() or list() - 看看这对 render_to_response 有什么影响。
  • 好的,我使用 list() 来强制评估查询集。它“神奇地”将加载时间从大约 2 分钟缩短到 15 秒。查看我的编辑。
  • 请问:为什么在 render_to_response 之前强制评估会大大减少我的加载​​时间?
  • @chiurox,魔法? :) 我不知道——这纯粹是直觉上的飞跃。当有疑问时,我倾向于将事情分解成更简单的步骤,以确认我真的知道发生了什么。鉴于强制 eval 确实有效果,看起来在您的 request.GET 和您的 render_to_response 之间“幕后”发生了一些奇怪的交互。也许其他人会对机制有更好的理解。
猜你喜欢
  • 2022-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-24
  • 2017-11-17
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多