python - 如何加速 Google Appengine 并消除超时?
问题描述
我在http://hue-histogram.appspot.com/在 Appengine 标准环境(免费试用)上部署了一个 Flask 应用程序。该应用程序的目的是根据本文计算色调直方图https://fstoppers.com/education/art-and-science-photography-color-theory-411739
虽然应用程序在 localhost(Flask 服务器)上运行顺畅,但在 Appengine 上它只适用于小图像(大约 2000 x 1500 像素和 2MB 文件)。对于较大的图像(4000 x 2500 像素,5MB 文件大小),它总是超时
500 错误:服务器错误 服务器遇到错误,无法完成您的请求。请在 30 秒后重试。
这是来自本地主机的代码。Appengine 上的唯一区别是我将 histogram.png 保存到 /tmp。
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import io
from PIL import Image, ImageDraw
from flask import Flask, render_template, request, send_file #, Response
#from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
#from matplotlib.figure import Figure
app = Flask(__name__)
@app.route('/')
def form():
return render_template('form.html')
@app.route('/hue-histogram', methods=['POST'])
def histogram():
fig = hue_histogram(request.files['image'])
im = Image.open('histogram.png')
img_io = io.BytesIO()
im.save(img_io, 'PNG')
img_io.seek(0)
return send_file(img_io, mimetype='image/png')
# THIS CODE DID NOT RETURN CORRECT IMAGE+PLOT OVERLAY
# HAD TO USE SAVEFIG TO HISTOGRAM.PNG INSTEAD
# output = io.BytesIO()
# FigureCanvas(fig).print_png(output)
# return Response(output.getvalue(), mimetype='image/png')
def hue_histogram(uploaded_image):
N = 24
im = Image.open(uploaded_image).convert("HSV")
radii = []
i=0
while i < N:
radii.append(0)
i = i + 1
hdat,sdat,vdat = im.split()
for h,s,v in zip(hdat.getdata(),sdat.getdata(),vdat.getdata()) :
i = int(h / (255 / N))
radii[i] = radii[i] + 1 #simple frequency based histogram
# radii[i] = radii[i] + s #saturation weighted
width,height = im.size
diameter = min(width,height)
left = (width - diameter)/2
top = (height - diameter)/2
right = (width + diameter)/2
bottom = (height + diameter)/2
im = Image.open(uploaded_image).convert("RGB")
# Crop the center of the image
im = im.crop((left, top, right, bottom))
npImage=np.array(im)
# Create same size alpha layer with circle
alpha = Image.new('L',im.size,0)
draw = ImageDraw.Draw(alpha)
draw.pieslice([0,0,diameter,diameter],0,360,fill=255)
# Convert alpha Image to numpy array
npAlpha=np.array(alpha)
# Add alpha layer to RGB
npImage=np.dstack((npImage,npAlpha))
im = Image.fromarray(npImage)
# Compute pie slices
theta = np.linspace(0.0, 2 * np.pi, N, endpoint=False)
width = 2 * np.pi / N
colors = plt.cm.hsv(theta/2/np.pi)
radiimax = max(radii)
i=0
while i < N:
radii[i] = radii[i] / radiimax
i = i + 1
fig = plt.figure(dpi=150)
ax0 = fig.add_axes([0.7, 0.7, 0.5, 0.5])
ax0.imshow(im)
ax0.axis("off")
ax = fig.add_axes([0.5, 0.5, 0.9, 0.9], polar=True, label="polar")
bars = ax.bar(theta, radii, width=width, bottom=1.3, color=colors)
ax.set_theta_direction(-1)
ax.set_theta_zero_location('N')
ax.set_facecolor("None")
ax.axis("off")
plt.savefig("histogram.png", bbox_inches = "tight")
return 'fig'
if __name__ == '__main__':
# app.debug = True #Uncomment to enable debugging
app.run() #Run the Server
对于如何优化代码和/或 Appengine 部署以便它可以处理甚至是大型 JPEG 文件的任何帮助,我将不胜感激。很多代码都是从 StackOverflow 上的不同代码片段粘合在一起的,所以我想有很大的潜力可以清理它,但它已经超出了我的初学者技能。:-)
解决方案
默认情况下,App Engine 的请求时间限制为 60 秒/请求。关于请求大小/响应时间等还有更多配额。您可以在此处查看所有配额和限制。
由于直方图的计算是一个需要更多时间的过程,因此我建议您将app.yaml 配置文件从automatic_scaling
更改basic_scaling.
为您可以在官方文档中看到,如果您使用basic__scaling
您的请求最多可以运行 24 小时。
编辑:
您可以尝试增加 max_instances 和 idle_timeout 参数(即使我认为您设置的已经足够了)。我会试着看看那些内存泄漏在哪里。
我还想提一下,在 App Engine 中使用 matplotlib时应该考虑一些特定的配置和限制。
例如,正如官方文档中所述:
pylab 和 matplotlib.pyplot 模块是有状态的,不是线程安全的。如果您在 App Engine 上使用它们,则必须在 app.yaml 中设置 threadsafe: false,并注意绘图仪状态将在同一实例上的请求之间保留。例如,您需要在每个请求开始时调用 pyplot.clf() 以确保以前的绘图不可见。建议您使用线程安全的面向对象 API 而不是有状态的 pyplot API。
我无法在您的代码中看到您正在调用 pyplot.clf()
方法。你的文件里也设置threadsafe : false
了吗?app.ymal
推荐阅读
- laravel - 如何为必须连接到 Laravel API 的 Vue SPA 运行带有 cypress e2e 测试的 Jenkins CI?
- python - 我的默认箱线图没有颜色
- javascript - 数组显示为空,但应该有一个元素
- acumatica - 无法用真值更新复选框
- eclipse - DSL 的 Xtext 验证
- matlab - MATLAB isequal 函数对符号表达式给出错误答案
- javascript - 如何在 flask_socketio 中“留出空间”?
- c - 在 C 中以下列方式初始化 struct 有什么区别?
- python-3.x - 尝试在 python3 中导入 tensorflow 时出现导入错误
- jquery - 如何使用jquery从销售表单中的附加行计算总金额