我有一个 Raspberry Pi 坐在一个偏远的地方。它连接到一个小型自制电路和一个温度探头。我已经设置了 Raspberry Pi 来做一些事情:
cron
每小时运行作业以读取温度并将其本地存储到 sqlite 数据库- 运行 Nginx 网络服务器
- 运行 uwsgi 应用服务器
- 提供一个简单的 Django 应用程序
在那个 Django 应用程序中,我有一个简单的视图,它执行以下操作:
- 点击 DB 获取最后 300 条温度记录
- 把它们放进熊猫
DataFrame
- 使用 Matplotlib 生成近期温度历史的漂亮 SVG 图
- 填写一个显示 SVG 的简单模板以及一个包含最近温度读数的小型 HTML 表格。
渲染此视图大约需要 30 秒。很长一段时间。所以我想看看是什么花了这么长时间。我的猜测是所有与生成图形相关的工作。但为了找出答案,我想做一些分析。
我安装django-debug-toolbar
并django-debug-toolbar-line-profiler
使用 pip。
我已经根据我所理解的文档对它们进行了配置。特别是,我设置了:
DEBUG = True
TEMPLATE_DEBUG = DEBUG
DEBUG_TOOLBAR_PATCH_SETTINGS = False
MIDDLEWARE_CLASSES = (
'debug_toolbar.middleware.DebugToolbarMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Uncomment the next line for simple clickjacking protection:
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
DEBUG_TOOLBAR_PANELS = (
'debug_toolbar.panels.versions.VersionsPanel',
'debug_toolbar.panels.timer.TimerPanel',
'debug_toolbar.panels.settings.SettingsPanel',
'debug_toolbar.panels.headers.HeadersPanel',
'debug_toolbar.panels.sql.SQLPanel',
'debug_toolbar.panels.staticfiles.StaticFilesPanel',
'debug_toolbar.panels.templates.TemplatesPanel',
'debug_toolbar.panels.cache.CachePanel',
'debug_toolbar.panels.signals.SignalsPanel',
'debug_toolbar.panels.logging.LoggingPanel',
'debug_toolbar.panels.redirects.RedirectsPanel',
'debug_toolbar_line_profiler.panel.ProfilingPanel',
)
此外,INTERNAL_IPS
也设置得当。
我已经使用基于类的视图构建了我的视图。它看起来像这样:
from django.views.generic import TemplateView
from XXXX.models import TempReading, TempSeries
import numpy as np
import pandas as pd
import matplotlib
from matplotlib.figure import Figure
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
import seaborn as sbn
import StringIO
class TestView(TemplateView):
template_name = 'XXXX/test.html'
def get_context_data(self, **kwargs):
upstairs = TempSeries.objects.get(name='Upstairs')
upstairstemps = upstairs.tempreading_set.all().order_by('-timestamp')[:300]
frame = pd.DataFrame(list(upstairstemps.values()))
frame.set_index('timestamp', inplace=True)
# matplotlib.rcParams['svg.fonttype'] = 'none'
fig = Figure()
ax = fig.add_subplot(1,1,1)
frame['value'].plot(ax=ax)
ax.get_xaxis().grid(color='w', linewidth=1)
ax.get_yaxis().grid(color='w', linewidth=1)
fig.set(facecolor='w')
canvas = FigureCanvas(fig)
imgdata = StringIO.StringIO()
canvas.print_svg(imgdata)
imgstr = imgdata.getvalue()
context = super(TestView, self).get_context_data(**kwargs)
context['svgtext'] = imgstr
context['htmltable'] = frame[:5].to_html()
return context
我对分析最感兴趣的代码是get_context_data
.
当我加载页面时,实际上会显示调试工具栏。并显示分析面板。但我看到的只是:
{method 'disable' of '_lsprof.Profiler' objects}
这是页面首次加载时的屏幕截图:
以下是它在分析页面上的外观:
它似乎根本没有做任何“线路分析”!我期望在基于类的视图中看到每一行的定时结果。特别是对于get_context_data
函数内的每一行。这是怎么回事?非常感谢任何帮助。
4月2日编辑
作为一个测试,我编写了一个不使用基于类的视图的虚拟视图。这似乎工作得很好。这是新的非基于类的视图:
def testview2(request):
df = pd.DataFrame({'a': np.random.randn(10), 'b': np.random.randn(10)})
htmltable = df.to_html()
context = {}
context['htmltable'] = htmltable
return render(request, 'XXXX/test2.html', context)
这会在分析窗格中产生以下结果:
所以这似乎工作正常。debug-toolbar-line-profiler
关于如何使用基于类的视图,我是否缺少一些微妙之处?在文档中,它建议它将分析类上不以下划线开头的任何方法。这是不正确的吗?