oro*_*ome 3 python matplotlib flask
Web搜索提供了几个简单的(未记录的)示例(以及这里的好答案)如何使用Flask动态提供Matplotlib数字; 但是有这些的特征,它们之间的差异让我感到困惑.
有些使用低级IO并返回元组
io = StringIO.StringIO()
plt.savefig(io, format='png')
io.seek(0)
data = io.read()
return data, 200, {'Content-type': 'image/png'}
Run Code Online (Sandbox Code Playgroud)
而其他几个 使用不同的IO API并返回一个Response
io = StringIO.StringIO()
canvas = FigureCanvas(fig)
canvas.print_png(io)
response = make_response(io.getvalue())
response.mimetype = 'image/png' # or response.headers['Content-Type'] = 'image/png'
return response
Run Code Online (Sandbox Code Playgroud)
而其他人则采用不同的方法来编码和构建返回值
io = StringIO.StringIO()
fig.savefig(io, format='png')
data = io.getvalue().encode('base64')
return html.format(data)
Run Code Online (Sandbox Code Playgroud)
所有这些似乎都有效; 但我想知道它们共享的方法是否有特征,或者它们之间的差异是否具有非明显的后果(例如性能或对不同场景的适用性).
第一,
StringIO; 它是准备服务图像(任何类型)的唯一方法吗?在我受保护的Python生活中,我以前从未见过它,并且不清楚为什么它似乎是服务器a(二进制文件)文件过程的必需部分.
其次,我想知道这些例子用来包装他们的反应的不同方法; 特别
seek加read,对getvalue,或这些做基本相同的事情;html.format对比Response(与make_response); 最后Content-type明确设置,而其他方法设置编码('base64')? 这些方法中的任何一种都被认为是"最佳"或最新的惯用(或至少是Pythonic)方法吗?
StringIO扮演的角色是什么; 它是准备服务图像(任何类型)的唯一方法吗?
首先,不,这不是唯一的方法."经典"方式是涉及文件系统:
write()).read()).步骤(3)和(4)涉及文件系统交互.也就是说,内核实际上与硬件组件对话.这需要时间(对于传统的hrad驱动器,只需几个字节写入光盘可能需要几毫秒,因为访问时间很长).现在,问题是:您是否需要将图像数据保存到磁盘?如果答案为"否",则可以通过将图像数据保留在Web应用程序进程的内存中来跳过与文件系统的整个交互并节省一些时间.这是StringIO有益的:
StringIO是Python中非常通用的工具,提供类似文件的对象,而实际数据永远不会委托给内核,以便将其写入文件系统或从文件系统中读取.它保存在记忆中.这就是StringIO对象也被称为内存中文件的原因.
关键是plt.savefig() 希望将一个对象作为第一个参数,它看起来像一个实际代表文件系统中真实文件的对象.StringIO提供了这样一个对象,但是 - 在引擎盖下 - 将数据写入当前进程的堆中的缓冲区,并在请求时再次从那里读取它.
通过StringIO纳秒或微秒读取/写入小部分数据,而与文件系统的交互通常是较慢的数量级.
现在,不要误会我的意思:通常,文件系统足够快,并且操作系统有自己的技术来尽可能快地进行文件系统交互.真正的问题是,如前所述:您是否需要保留图像数据?如果您稍后不关心访问此图像数据,则不要涉及文件系统.这就是你展示的三个片段的创建者所决定的.
出于性能原因替换与StringIO的实际文件系统交互可能是一个非常有效的决策.但是,在您的Web应用程序中肯定存在其他瓶颈.例如,使用StringIO可以减少请求 - 响应延迟,比如说5 ms.但考虑到100毫秒的网络延迟,这实际上是否重要?此外,请记住,一个严肃的Web应用程序最好不要被发送大文件内容所困扰 - 这些更好地服务于一个完善的Web服务器,它也可以使用sendfile()系统调用.在这种情况下,让matplotlib将文件写入文件系统然后告诉您的Web服务器(通过X-Sendfile标题)做其余的事情.因此,性能是一个复杂的话题可能不是最强的论据.但只有你知道你的要求!
使用seek plus read,get getvalue是否有任何意义,或者这些基本上是相同的
基本上是一样的.不会产生概念上的差异,也不会产生(重大)性能差异.
是什么决定了返回的方法之间的选择:元组与html.format对比响应(使用make_response); 最后
没有明确的答案.有很多方法可以将数据传输到客户端.没有"正确"的方法,只是更好或更糟.哪种方法最强烈取决于Web框架.使用Flask,make_response()是创建响应对象的规范方法.html.format()可能有一些我不知道的优点 - 你需要自己阅读!但是,请继续阅读,我认为Flask内置了一种方法,非常适合您的场景.
为什么有些方法明确设置Content-type,而其他方法设置编码('base64')?
有正确和不正确的方法通过HTTP将文件发送到浏览器.通常,HTTP响应应包含某些标头(另请参阅需要哪些HTTP响应标头).只是为了您的理解,您可能想了解这些细节.当然,二进制数据需要使用客户端理解的编码进行编码,并且必须在响应头中阐明编码.此外,正确的HTTP响应应包含MIME类型(内容类型).你提出的方法似乎并没有真正掌控一个或另一个(没有冒犯,快速和肮脏的例子往往更多地关注一件事而不是另一件事).
我认为你真的应该使用Flask的send_file方法来处理一些重要的事情.这种方法有几个参数.我会明确定义MIME类型mimetype.第一个参数可以是类文件对象,因此StringIO对象可以正常工作.但是,在这种情况下你需要做的事情seek(0):
在调用send_file()之前,确保文件指针位于要发送的数据的开头.
以下两种方法在语义上都很优雅(在我看来),并且应该适当注意编码文件内容和设置HTTP响应头:
from flask import send_file
Run Code Online (Sandbox Code Playgroud)
1)
f = StringIO.StringIO()
plt.savefig(f, format='png', dpi=300)
f.seek(0)
send_file(f, mimetype='image/png')
Run Code Online (Sandbox Code Playgroud)
2)
plt.savefig('image.png', dpi=300)
send_file('image.png', mimetype='image/png')
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,如果配置正确,您的网络服务器(例如nginx)可以为您传输文件.
| 归档时间: |
|
| 查看次数: |
372 次 |
| 最近记录: |