我正在比较我的一个旧的PHP脚本与较新的,更高级的Django版本和PHP版本,完全吐出HTML并且所有功能都运行得更快。更快到Django上的某些东西必须出错。
首先,一些背景信息:我有一个页面可以显示销售数据的报告。数据可以通过许多方式进行过滤,但大部分都是按日期过滤的。这使得缓存它有点困难,因为结果的可能性几乎是无穷无尽的。有很多数字和计算已完成,但在PHP中处理它并不是一个很大的问题。
更新
经过一些额外的测试后,我的视图中没有任何内容导致减速。如果我只是对数据进行数字处理并吐出5行渲染的HTML,那就不那么慢(仍然比PHP慢),但如果我渲染了大量数据,那就非常慢了。
每当我运行大型报告(例如当年的所有销售)时,机器的CPU使用率都会达到100%。不知道这是否意味着什么。我正在使用mod_python和Apache。也许转换到WSGI可能会有所帮助吗?
我的模板标签显示小计/总计处理的时间从0.1秒到1秒,适用于非常大的集合。我在报告中称他们为6次,所以他们似乎不是最大的问题。
现在,我运行了一个Python分析器并返回了这些结果:
Ordered by: internal time List reduced from 3074 to 20 due to restriction ncalls tottime percall cumtime percall filename:lineno(function) 2939417 26.290 0.000 44.857 0.000 /usr/lib/python2.5/tokenize.py:212(generate_tokens) 2822655 17.049 0.000 17.049 0.000 {built-in method match} 1689928 15.418 0.000 23.297 0.000 /usr/lib/python2.5/decimal.py:515(__new__) 12289605 11.464 0.000 11.464 0.000 {isinstance} 882618 9.614 0.000 25.518 0.000 /usr/lib/python2.5/decimal.py:1447(_fix) 17393 8.742 0.001 60.798 0.003 /usr/lib/python2.5/tokenize.py:158(tokenize_loop) 11 7.886 0.717 7.886 0.717 {method 'accept' of '_socket.socket' objects} 365577 7.854 0.000 30.233 0.000 /usr/lib/python2.5/decimal.py:954(__add__) 2922024 7.199 0.000 7.199 0.000 /usr/lib/python2.5/inspect.py:571(tokeneater) 438750 5.868 0.000 31.033 0.000 /usr/lib/python2.5/decimal.py:1064(__mul__) 60799 5.666 0.000 9.377 0.000 /usr/lib/python2.5/site-packages/django/db/models/base.py:241(__init__) 17393 4.734 0.000 4.734 0.000 {method 'query' of '_mysql.connection' objects} 1124348 4.631 0.000 8.469 0.000 /usr/lib/python2.5/site-packages/django/utils/encoding.py:44(force_unicode) 219076 4.139 0.000 156.618 0.001 /usr/lib/python2.5/site-packages/django/template/__init__.py:700(_resolve_lookup) 1074478 3.690 0.000 11.096 0.000 /usr/lib/python2.5/decimal.py:5065(_convert_other) 2973281 3.424 0.000 3.424 0.000 /usr/lib/python2.5/decimal.py:718(__nonzero__) 759014 2.962 0.000 3.371 0.000 /usr/lib/python2.5/decimal.py:4675(__init__) 381756 2.806 0.000 128.447 0.000 /usr/lib/python2.5/site-packages/django/db/models/fields/related.py:231(__get__) 842130 2.764 0.000 3.557 0.000 /usr/lib/python2.5/decimal.py:3339(_dec_from_triple)
tokenize.py出现在顶部,这可以说明一点,因为我正在进行大量的数字格式化。 Decimal.py很有意义,因为报告基本上是90%的数字。我不知道内置方法match
是什么,因为我没有在我自己的代码中做任何正则表达式或类似的东西(Django正在做什么?)最接近的是我使用的是itertools ifilter。
这似乎是主要的罪魁祸首,如果我能弄清楚如何减少那些处理时间,那么我会有一个更快的页面。
有没有人对如何开始减少这个有任何建议?我真的不知道如何解决这个令牌化/小数问题,而不是简单地删除它们。
更新:我在大多数数据上运行了一些带/不带过滤器的测试,结果时间几乎相同,后者速度稍快但不是问题的原因。 tokenize.py到底发生了什么?
答案 0 :(得分:6)
由于您没有任何类型的代码示例,因此有很多事情要考虑您的问题。
以下是我的假设:您正在使用Django的内置ORM工具和模型(即sales-data = modelobj.objects()。all()),在PHP方面,您正在处理直接SQL查询和使用一个query_set。
Django正在进行大量的类型转换和转换,数据类型从数据库查询到ORM / Model对象和关联的管理器(默认情况下为objects())。
在PHP中,您控制转换并确切知道如何从一种数据类型转换为另一种数据类型,您只需基于该问题节省一些执行时间。
我建议尝试将一些奇特的数字工作移到数据库中,特别是如果你正在进行基于记录集的处理 - 数据库从早餐中吃掉那种处理方式。在Django中,您可以将RAW SQL发送到数据库:http://docs.djangoproject.com/en/dev/topics/db/sql/#topics-db-sql
我希望这至少可以让你指出正确的方向......
答案 1 :(得分:2)
“tokenize.py出现在最顶层,这可以说明我正在进行大量的数字格式化。”
毫无意义。
请参阅http://docs.python.org/library/tokenize.html。
tokenize模块提供了一个词法 用于Python源代码的扫描程序, 用Python实现
Tokenize名列前茅意味着您正在进行动态代码解析。
AFAIK(在Django存储库上搜索)Django不使用tokenize。这样就可以让你的程序进行某种动态代码实例化。或者,您只是分析程序加载,解析和运行的第一个时间,导致对时间的错误假设。
你应该不在模板标签中进行计算 - 这很慢。它涉及模板标签的复杂元评估。您应该在简单,低开销的Python中在视图中进行所有计算。使用模板仅用于演示。
此外,如果您经常进行查询,过滤,总结以及什么不是,那么您就拥有了一个数据仓库。获取有关数据仓库设计的书籍,并遵循数据仓库设计模式。
您必须有一个中心事实表,由维度表包围。这非常非常有效。
Sums,group bys等可以在Python中作为defaultdict
操作完成。批量获取所有行,使用所需结果构建字典。如果这太慢了,那么你必须使用数据仓库技术来保存持久的总和和你的细粒度事实。这通常涉及走出Django ORM并使用RDBMS功能,如视图或派生数据表。
答案 2 :(得分:2)
在处理大量数据时,您还可以使用更直接访问查询结果的ValuesQuerySet来节省大量CPU和内存,而不是为结果中的每一行创建模型对象实例。
它的用法看起来有点像这样:
Blog.objects.order_by('id').values()
答案 3 :(得分:1)
在这种情况下,数据库通常是瓶颈。此外,使用ORM可能会导致次优的SQL查询。
正如一些人所指出的那样,只能根据你提供的信息来判断探测器究竟是什么。
我可以给你一些一般的建议: