Django-debug-toolbar-line-profiler只显示一行输出,没有内容
我有一个树莓派放在一个偏远的地方。它连接着一个小的自制电路和一个温度探头。我已经设置了树莓派来做几件事情:
- 每小时运行一次
cron
任务,读取温度并将其存储到本地的sqlite数据库中 - 运行一个Nginx网页服务器
- 运行一个uwsgi应用服务器
- 提供一个简单的Django应用
在这个Django应用中,我有一个简单的视图,做了以下几件事:
- 从数据库获取最近的300条温度记录
- 把这些记录放到一个Pandas的
DataFrame
中 - 使用Matplotlib生成一个漂亮的SVG图表,显示最近的温度变化
- 填充一个简单的模板,展示这个SVG图表和最近温度记录的小HTML表格。
渲染这个视图大约需要30秒。真是太长了。所以我想看看是什么原因导致这么慢。我猜可能是生成图形的工作太多了。但为了确认,我想做一些性能分析。
我通过pip安装了django-debug-toolbar
和django-debug-toolbar-line-profiler
。
我根据文档尽量配置了它们。特别是,我设置了:
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
与基于类的视图如何配合使用的一些细节?文档中提到它会分析类中所有不以下划线开头的方法。这是错误的吗?
2 个回答
既然你是在某个芯片上运行这个程序,我强烈建议你把服务器端的工作尽量简化,把复杂的逻辑处理放到客户端去做。
没错,JavaScript的能力和Python差不多,而且这些处理不会在你的服务器上进行。所有的图形绘制,甚至模板渲染,都应该放到客户端去做。这样做肯定能减少在像芯片这样的设备上加载页面的时间。
至于调试,为什么不先在真正的电脑上调试一下,然后再移到树莓派上呢?你可以加一些简单的日志记录,来标记你想要检查的部分。
我发现当我给我的视图加上了 @csrf_exempt
这个装饰器后,就出现了问题;一旦把它去掉,性能分析工具就正常工作了。
我不太清楚为什么会导致这个问题,但这样做解决了我的困扰。