首页 > 解决方案 > 如何加速 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 上的不同代码片段粘合在一起的,所以我想有很大的潜力可以清理它,但它已经超出了我的初学者技能。:-)

标签: pythongoogle-app-engineflaskcolors

解决方案


默认情况下,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


推荐阅读